1
Fork 0

Parse and typecheck (not kindcheck) bounds on trait paths.

This commit is contained in:
Ben Blum 2013-06-17 15:16:30 -04:00
parent 394f455b5e
commit ce857e3d60
37 changed files with 197 additions and 121 deletions

View file

@ -954,7 +954,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_name(ecx, ebml_w, item.ident); encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs); encode_attributes(ebml_w, item.attrs);
match ty.node { match ty.node {
ast::ty_path(path, _) if path.idents.len() == 1 => { ast::ty_path(path, bounds, _) if path.idents.len() == 1 => {
assert!(bounds.is_empty());
encode_impl_type_basename(ecx, ebml_w, encode_impl_type_basename(ecx, ebml_w,
ast_util::path_to_ident(path)); ast_util::path_to_ident(path));
} }

View file

@ -311,8 +311,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
let substs = parse_substs(st, conv); let substs = parse_substs(st, conv);
let store = parse_trait_store(st); let store = parse_trait_store(st);
let mt = parse_mutability(st); let mt = parse_mutability(st);
let bounds = parse_bounds(st, conv);
assert_eq!(next(st), ']'); assert_eq!(next(st), ']');
return ty::mk_trait(st.tcx, def, substs, store, mt); return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds);
} }
'p' => { 'p' => {
let did = parse_def(st, TypeParameter, conv); let did = parse_def(st, TypeParameter, conv);

View file

@ -261,13 +261,16 @@ fn enc_sty(w: @io::Writer, cx: @ctxt, st: ty::sty) {
enc_substs(w, cx, substs); enc_substs(w, cx, substs);
w.write_char(']'); w.write_char(']');
} }
ty::ty_trait(def, ref substs, store, mt) => { ty::ty_trait(def, ref substs, store, mt, bounds) => {
w.write_str(&"x["); w.write_str(&"x[");
w.write_str((cx.ds)(def)); w.write_str((cx.ds)(def));
w.write_char('|'); w.write_char('|');
enc_substs(w, cx, substs); enc_substs(w, cx, substs);
enc_trait_store(w, cx, store); enc_trait_store(w, cx, store);
enc_mutability(w, mt); enc_mutability(w, mt);
let bounds = ty::ParamBounds {builtin_bounds: bounds,
trait_bounds: ~[]};
enc_bounds(w, cx, &bounds);
w.write_char(']'); w.write_char(']');
} }
ty::ty_tup(ts) => { ty::ty_tup(ts) => {

View file

@ -129,7 +129,8 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
if cx.tcx.lang_items.drop_trait() == trait_def_id { if cx.tcx.lang_items.drop_trait() == trait_def_id {
// Yes, it's a destructor. // Yes, it's a destructor.
match self_type.node { match self_type.node {
ty_path(_, path_node_id) => { ty_path(_, bounds, path_node_id) => {
assert!(bounds.is_empty());
let struct_def = cx.tcx.def_map.get_copy( let struct_def = cx.tcx.def_map.get_copy(
&path_node_id); &path_node_id);
let struct_did = let struct_did =
@ -307,7 +308,7 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) { fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) {
match aty.node { match aty.node {
ty_path(_, id) => { ty_path(_, _, id) => {
let r = cx.tcx.node_type_substs.find(&id); let r = cx.tcx.node_type_substs.find(&id);
for r.iter().advance |ts| { for r.iter().advance |ts| {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id)); let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id));
@ -533,7 +534,8 @@ pub fn check_cast_for_escaping_regions(
pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) { pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) {
let target_ty = ty::expr_ty(cx.tcx, target); let target_ty = ty::expr_ty(cx.tcx, target);
match ty::get(target_ty).sty { match ty::get(target_ty).sty {
ty::ty_trait(_, _, ty::UniqTraitStore, _) => { // FIXME(#3569) kind check bounds here
ty::ty_trait(_, _, ty::UniqTraitStore, _, _bounds) => {
let source_ty = ty::expr_ty(cx.tcx, source); let source_ty = ty::expr_ty(cx.tcx, source);
if !ty::type_is_owned(cx.tcx, source_ty) { if !ty::type_is_owned(cx.tcx, source_ty) {
cx.tcx.sess.span_err( cx.tcx.sess.span_err(

View file

@ -714,7 +714,7 @@ fn check_item_ctypes(cx: &Context, it: @ast::item) {
let tys = vec::map(decl.inputs, |a| a.ty ); let tys = vec::map(decl.inputs, |a| a.ty );
for vec::each(vec::append_one(tys, decl.output)) |ty| { for vec::each(vec::append_one(tys, decl.output)) |ty| {
match ty.node { match ty.node {
ast::ty_path(_, id) => { ast::ty_path(_, _, id) => {
match cx.tcx.def_map.get_copy(&id) { match cx.tcx.def_map.get_copy(&id) {
ast::def_prim_ty(ast::ty_int(ast::ty_i)) => { ast::def_prim_ty(ast::ty_int(ast::ty_i)) => {
cx.span_lint(ctypes, ty.span, cx.span_lint(ctypes, ty.span,

View file

@ -804,7 +804,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
// then check whether it is region-parameterized and consider // then check whether it is region-parameterized and consider
// that as a direct dependency. // that as a direct dependency.
match ty.node { match ty.node {
ast::ty_path(path, id) => { ast::ty_path(path, _bounds, id) => {
match cx.def_map.find(&id) { match cx.def_map.find(&id) {
Some(&ast::def_ty(did)) | Some(&ast::def_ty(did)) |
Some(&ast::def_trait(did)) | Some(&ast::def_trait(did)) |
@ -840,7 +840,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
visit_mt(mt, (cx, visitor)); visit_mt(mt, (cx, visitor));
} }
ast::ty_path(path, _) => { ast::ty_path(path, _bounds, _) => {
// type parameters are---for now, anyway---always invariant // type parameters are---for now, anyway---always invariant
do cx.with_ambient_variance(rv_invariant) { do cx.with_ambient_variance(rv_invariant) {
for path.types.iter().advance |tp| { for path.types.iter().advance |tp| {

View file

@ -1250,7 +1250,7 @@ impl Resolver {
// If there are static methods, then create the module // If there are static methods, then create the module
// and add them. // and add them.
match (trait_ref_opt, ty) { match (trait_ref_opt, ty) {
(None, @Ty { node: ty_path(path, _), _ }) if (None, @Ty { node: ty_path(path, _, _), _ }) if
has_static_methods && path.idents.len() == 1 => { has_static_methods && path.idents.len() == 1 => {
let name = path_to_ident(path); let name = path_to_ident(path);
@ -4120,7 +4120,7 @@ impl Resolver {
// Like path expressions, the interpretation of path types depends // Like path expressions, the interpretation of path types depends
// on whether the path has multiple elements in it or not. // on whether the path has multiple elements in it or not.
ty_path(path, path_id) => { ty_path(path, bounds, path_id) => {
// This is a path in the type namespace. Walk through scopes // This is a path in the type namespace. Walk through scopes
// scopes looking for it. // scopes looking for it.
let mut result_def = None; let mut result_def = None;
@ -4179,6 +4179,10 @@ impl Resolver {
self.idents_to_str(path.idents))); self.idents_to_str(path.idents)));
} }
} }
for bounds.each |bound| {
self.resolve_type_parameter_bound(bound, visitor);
}
} }
ty_closure(c) => { ty_closure(c) => {

View file

@ -561,7 +561,7 @@ fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType {
cx.sess.span_note(span, "debuginfo for closure NYI"); cx.sess.span_note(span, "debuginfo for closure NYI");
create_unimpl_ty(cx, t) create_unimpl_ty(cx, t)
}, },
ty::ty_trait(_did, ref _substs, ref _vstore, _) => { ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => {
cx.sess.span_note(span, "debuginfo for trait NYI"); cx.sess.span_note(span, "debuginfo for trait NYI");
create_unimpl_ty(cx, t) create_unimpl_ty(cx, t)
}, },

View file

@ -683,7 +683,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
} }
ast::expr_cast(val, _) => { ast::expr_cast(val, _) => {
match ty::get(node_id_type(bcx, expr.id)).sty { match ty::get(node_id_type(bcx, expr.id)).sty {
ty::ty_trait(_, _, store, _) => { ty::ty_trait(_, _, store, _, _) => {
return meth::trans_trait_cast(bcx, val, expr.id, dest, return meth::trans_trait_cast(bcx, val, expr.id, dest,
store); store);
} }

View file

@ -486,13 +486,13 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
ty::ty_closure(_) => { ty::ty_closure(_) => {
closure::make_closure_glue(bcx, v0, t, drop_ty) closure::make_closure_glue(bcx, v0, t, drop_ty)
} }
ty::ty_trait(_, _, ty::BoxTraitStore, _) => { ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]); let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
let llbox = Load(bcx, llbox_ptr); let llbox = Load(bcx, llbox_ptr);
decr_refcnt_maybe_free(bcx, llbox, Some(llbox_ptr), decr_refcnt_maybe_free(bcx, llbox, Some(llbox_ptr),
ty::mk_opaque_box(ccx.tcx)) ty::mk_opaque_box(ccx.tcx))
} }
ty::ty_trait(_, _, ty::UniqTraitStore, _) => { ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]); let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
// Only drop the value when it is non-null // Only drop the value when it is non-null
do with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue))) |bcx| { do with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue))) |bcx| {
@ -571,12 +571,12 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
ty::ty_closure(_) => { ty::ty_closure(_) => {
closure::make_closure_glue(bcx, v, t, take_ty) closure::make_closure_glue(bcx, v, t, take_ty)
} }
ty::ty_trait(_, _, ty::BoxTraitStore, _) => { ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box])); let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
incr_refcnt_of_boxed(bcx, llbox); incr_refcnt_of_boxed(bcx, llbox);
bcx bcx
} }
ty::ty_trait(_, _, ty::UniqTraitStore, _) => { ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]); let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable])); let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable]));

View file

@ -293,7 +293,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
ty::ty_closure(ref fty) => { ty::ty_closure(ref fty) => {
Some(normalized_closure_ty(tcx, fty.sigil)) Some(normalized_closure_ty(tcx, fty.sigil))
} }
ty::ty_trait(_, _, ref store, _) => { ty::ty_trait(_, _, ref store, _, _) => {
let sigil = match *store { let sigil = match *store {
ty::UniqTraitStore => ast::OwnedSigil, ty::UniqTraitStore => ast::OwnedSigil,
ty::BoxTraitStore => ast::ManagedSigil, ty::BoxTraitStore => ast::ManagedSigil,

View file

@ -160,7 +160,7 @@ fn traverse_ty<'a>(ty: @Ty, (cx, v): (@mut ctx<'a>, visit::vt<@mut ctx<'a>>)) {
} }
match ty.node { match ty.node {
ty_path(p, p_id) => { ty_path(p, _bounds, p_id) => {
match cx.tcx.def_map.find(&p_id) { match cx.tcx.def_map.find(&p_id) {
// Kind of a hack to check this here, but I'm not sure what else // Kind of a hack to check this here, but I'm not sure what else
// to do // to do

View file

@ -335,7 +335,7 @@ impl Reflector {
} }
// Miscallaneous extra types // Miscallaneous extra types
ty::ty_trait(_, _, _, _) => self.leaf(~"trait"), ty::ty_trait(_, _, _, _, _) => self.leaf(~"trait"),
ty::ty_infer(_) => self.leaf(~"infer"), ty::ty_infer(_) => self.leaf(~"infer"),
ty::ty_err => self.leaf(~"err"), ty::ty_err => self.leaf(~"err"),
ty::ty_param(ref p) => { ty::ty_param(ref p) => {

View file

@ -140,7 +140,7 @@ pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> Type {
ty::ty_bare_fn(*) => Type::i8p(), ty::ty_bare_fn(*) => Type::i8p(),
ty::ty_closure(*) => Type::struct_([Type::i8p(), Type::i8p()], false), ty::ty_closure(*) => Type::struct_([Type::i8p(), Type::i8p()], false),
ty::ty_trait(_, _, store, _) => Type::opaque_trait(cx, store), ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store),
ty::ty_estr(ty::vstore_fixed(size)) => Type::array(&Type::i8(), size as u64), ty::ty_estr(ty::vstore_fixed(size)) => Type::array(&Type::i8(), size as u64),
ty::ty_evec(mt, ty::vstore_fixed(size)) => { ty::ty_evec(mt, ty::vstore_fixed(size)) => {
@ -271,7 +271,7 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
let ty = type_of_fn_from_ty(cx, t); let ty = type_of_fn_from_ty(cx, t);
Type::func_pair(cx, &ty) Type::func_pair(cx, &ty)
} }
ty::ty_trait(_, _, store, _) => Type::opaque_trait(cx, store), ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store),
ty::ty_type => cx.tydesc_type.ptr_to(), ty::ty_type => cx.tydesc_type.ptr_to(),
ty::ty_tup(*) => { ty::ty_tup(*) => {
let repr = adt::represent_type(cx, t); let repr = adt::represent_type(cx, t);

View file

@ -208,7 +208,7 @@ pub fn type_needs_inner(cx: Context,
ty::ty_bare_fn(*) | ty::ty_bare_fn(*) |
ty::ty_ptr(_) | ty::ty_ptr(_) |
ty::ty_rptr(_, _) | ty::ty_rptr(_, _) |
ty::ty_trait(_, _, _, _) => false, ty::ty_trait(*) => false,
ty::ty_enum(did, ref substs) => { ty::ty_enum(did, ref substs) => {
if list::find(enums_seen, |id| *id == did).is_none() { if list::find(enums_seen, |id| *id == did).is_none() {

View file

@ -419,7 +419,8 @@ impl to_bytes::IterBytes for ClosureTy {
self.sigil.iter_bytes(lsb0, f) && self.sigil.iter_bytes(lsb0, f) &&
self.onceness.iter_bytes(lsb0, f) && self.onceness.iter_bytes(lsb0, f) &&
self.region.iter_bytes(lsb0, f) && self.region.iter_bytes(lsb0, f) &&
self.sig.iter_bytes(lsb0, f) self.sig.iter_bytes(lsb0, f) &&
self.bounds.iter_bytes(lsb0, f)
} }
} }
@ -600,7 +601,7 @@ pub enum sty {
ty_rptr(Region, mt), ty_rptr(Region, mt),
ty_bare_fn(BareFnTy), ty_bare_fn(BareFnTy),
ty_closure(ClosureTy), ty_closure(ClosureTy),
ty_trait(def_id, substs, TraitStore, ast::mutability), ty_trait(def_id, substs, TraitStore, ast::mutability, BuiltinBounds),
ty_struct(def_id, substs), ty_struct(def_id, substs),
ty_tup(~[t]), ty_tup(~[t]),
@ -1046,7 +1047,7 @@ fn mk_t(cx: ctxt, st: sty) -> t {
&ty_infer(_) => flags |= needs_infer as uint, &ty_infer(_) => flags |= needs_infer as uint,
&ty_self(_) => flags |= has_self as uint, &ty_self(_) => flags |= has_self as uint,
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) | &ty_enum(_, ref substs) | &ty_struct(_, ref substs) |
&ty_trait(_, ref substs, _, _) => { &ty_trait(_, ref substs, _, _, _) => {
flags |= sflags(substs); flags |= sflags(substs);
} }
&ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) | &ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) |
@ -1268,10 +1269,11 @@ pub fn mk_trait(cx: ctxt,
did: ast::def_id, did: ast::def_id,
substs: substs, substs: substs,
store: TraitStore, store: TraitStore,
mutability: ast::mutability) mutability: ast::mutability,
bounds: BuiltinBounds)
-> t { -> t {
// take a copy of substs so that we own the vectors inside // take a copy of substs so that we own the vectors inside
mk_t(cx, ty_trait(did, substs, store, mutability)) mk_t(cx, ty_trait(did, substs, store, mutability, bounds))
} }
pub fn mk_struct(cx: ctxt, struct_id: ast::def_id, substs: substs) -> t { pub fn mk_struct(cx: ctxt, struct_id: ast::def_id, substs: substs) -> t {
@ -1319,7 +1321,7 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) {
maybe_walk_ty(tm.ty, f); maybe_walk_ty(tm.ty, f);
} }
ty_enum(_, ref substs) | ty_struct(_, ref substs) | ty_enum(_, ref substs) | ty_struct(_, ref substs) |
ty_trait(_, ref substs, _, _) => { ty_trait(_, ref substs, _, _, _) => {
for (*substs).tps.iter().advance |subty| { maybe_walk_ty(*subty, f); } for (*substs).tps.iter().advance |subty| { maybe_walk_ty(*subty, f); }
} }
ty_tup(ref ts) => { for ts.iter().advance |tt| { maybe_walk_ty(*tt, f); } } ty_tup(ref ts) => { for ts.iter().advance |tt| { maybe_walk_ty(*tt, f); } }
@ -1380,8 +1382,8 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty {
ty_enum(tid, ref substs) => { ty_enum(tid, ref substs) => {
ty_enum(tid, fold_substs(substs, fldop)) ty_enum(tid, fold_substs(substs, fldop))
} }
ty_trait(did, ref substs, st, mutbl) => { ty_trait(did, ref substs, st, mutbl, bounds) => {
ty_trait(did, fold_substs(substs, fldop), st, mutbl) ty_trait(did, fold_substs(substs, fldop), st, mutbl, bounds)
} }
ty_tup(ref ts) => { ty_tup(ref ts) => {
let new_ts = ts.map(|tt| fldop(*tt)); let new_ts = ts.map(|tt| fldop(*tt));
@ -1470,8 +1472,12 @@ pub fn fold_regions_and_ty(
ty_struct(def_id, ref substs) => { ty_struct(def_id, ref substs) => {
ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt)) ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt))
} }
ty_trait(def_id, ref substs, st, mutbl) => { ty_trait(def_id, ref substs, st, mutbl, bounds) => {
ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl) let st = match st {
RegionTraitStore(region) => RegionTraitStore(fldr(region)),
st => st,
};
ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl, bounds)
} }
ty_bare_fn(ref f) => { ty_bare_fn(ref f) => {
ty::mk_bare_fn(cx, BareFnTy {sig: fold_sig(&f.sig, fldfnt), ty::mk_bare_fn(cx, BareFnTy {sig: fold_sig(&f.sig, fldfnt),
@ -2054,18 +2060,18 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache))) TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache)))
} }
ty_trait(_, _, UniqTraitStore, _) => { ty_trait(_, _, UniqTraitStore, _, _bounds) => {
TC_OWNED_CLOSURE TC_OWNED_CLOSURE
} }
ty_trait(_, _, BoxTraitStore, mutbl) => { ty_trait(_, _, BoxTraitStore, mutbl, _bounds) => {
match mutbl { match mutbl {
ast::m_mutbl => TC_MANAGED + TC_MUTABLE, ast::m_mutbl => TC_MANAGED + TC_MUTABLE,
_ => TC_MANAGED _ => TC_MANAGED
} }
} }
ty_trait(_, _, RegionTraitStore(r), mutbl) => { ty_trait(_, _, RegionTraitStore(r), mutbl, _bounds) => {
borrowed_contents(r, mutbl) borrowed_contents(r, mutbl)
} }
@ -2347,7 +2353,7 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
false // unsafe ptrs can always be NULL false // unsafe ptrs can always be NULL
} }
ty_trait(_, _, _, _) => { ty_trait(_, _, _, _, _) => {
false false
} }
@ -2500,7 +2506,7 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
ty_box(_) | ty_uniq(_) | ty_closure(_) | ty_box(_) | ty_uniq(_) | ty_closure(_) |
ty_estr(vstore_uniq) | ty_estr(vstore_box) | ty_estr(vstore_uniq) | ty_estr(vstore_box) |
ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) | ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) |
ty_trait(_, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false, ty_trait(_, _, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
// Structural types // Structural types
ty_enum(did, ref substs) => { ty_enum(did, ref substs) => {
let variants = enum_variants(cx, did); let variants = enum_variants(cx, did);
@ -2791,12 +2797,13 @@ impl to_bytes::IterBytes for sty {
ty_uniq(ref mt) => 19u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), ty_uniq(ref mt) => 19u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f),
ty_trait(ref did, ref substs, ref v, ref mutbl) => { ty_trait(ref did, ref substs, ref v, ref mutbl, bounds) => {
20u8.iter_bytes(lsb0, f) && 20u8.iter_bytes(lsb0, f) &&
did.iter_bytes(lsb0, f) && did.iter_bytes(lsb0, f) &&
substs.iter_bytes(lsb0, f) && substs.iter_bytes(lsb0, f) &&
v.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f) &&
mutbl.iter_bytes(lsb0, f) mutbl.iter_bytes(lsb0, f) &&
bounds.iter_bytes(lsb0, f)
} }
ty_opaque_closure_ptr(ref ck) => 21u8.iter_bytes(lsb0, f) && ck.iter_bytes(lsb0, f), ty_opaque_closure_ptr(ref ck) => 21u8.iter_bytes(lsb0, f) && ck.iter_bytes(lsb0, f),
@ -3440,7 +3447,7 @@ pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
ty_rptr(_, _) => ~"&-ptr", ty_rptr(_, _) => ~"&-ptr",
ty_bare_fn(_) => ~"extern fn", ty_bare_fn(_) => ~"extern fn",
ty_closure(_) => ~"fn", ty_closure(_) => ~"fn",
ty_trait(id, _, _, _) => fmt!("trait %s", item_path_str(cx, id)), ty_trait(id, _, _, _, _) => fmt!("trait %s", item_path_str(cx, id)),
ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)), ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)),
ty_tup(_) => ~"tuple", ty_tup(_) => ~"tuple",
ty_infer(TyVar(_)) => ~"inferred type", ty_infer(TyVar(_)) => ~"inferred type",
@ -3774,7 +3781,7 @@ pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> { pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
match get(ty).sty { match get(ty).sty {
ty_trait(id, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id), ty_trait(id, _, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
_ => None _ => None
} }
} }
@ -4454,5 +4461,6 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name)); assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name));
let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name); let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name);
(trait_ref, (trait_ref,
mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore, ast::m_imm)) mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs,
BoxTraitStore, ast::m_imm, EmptyBuiltinBounds()))
} }

View file

@ -277,7 +277,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
} }
return ty::mk_evec(tcx, mt, vst); return ty::mk_evec(tcx, mt, vst);
} }
ast::ty_path(path, id) => { ast::ty_path(path, bounds, id) => {
// Note that the "bounds must be empty if path is not a trait"
// restriction is enforced in the below case for ty_path, which
// will run after this as long as the path isn't a trait.
match tcx.def_map.find(&id) { match tcx.def_map.find(&id) {
Some(&ast::def_prim_ty(ast::ty_str)) if a_seq_ty.mutbl == ast::m_imm => { Some(&ast::def_prim_ty(ast::ty_str)) if a_seq_ty.mutbl == ast::m_imm => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS); check_path_args(tcx, path, NO_TPS | NO_REGIONS);
@ -300,11 +303,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
ty::BoxTraitStore ty::BoxTraitStore
} }
}; };
let bounds = conv_builtin_bounds(this.tcx(), bounds);
return ty::mk_trait(tcx, return ty::mk_trait(tcx,
result.def_id, result.def_id,
copy result.substs, copy result.substs,
trait_store, trait_store,
a_seq_ty.mutbl); a_seq_ty.mutbl,
bounds);
} }
_ => {} _ => {}
} }
@ -395,13 +400,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
ast_ty.span); ast_ty.span);
ty::mk_closure(tcx, fn_decl) ty::mk_closure(tcx, fn_decl)
} }
ast::ty_path(path, id) => { ast::ty_path(path, bounds, id) => {
let a_def = match tcx.def_map.find(&id) { let a_def = match tcx.def_map.find(&id) {
None => tcx.sess.span_fatal( None => tcx.sess.span_fatal(
ast_ty.span, fmt!("unbound path %s", ast_ty.span, fmt!("unbound path %s",
path_to_str(path, tcx.sess.intr()))), path_to_str(path, tcx.sess.intr()))),
Some(&d) => d Some(&d) => d
}; };
// Kind bounds on path types are only supported for traits.
match a_def {
// But don't emit the error if the user meant to do a trait anyway.
ast::def_trait(*) => { },
_ if !bounds.is_empty() =>
tcx.sess.span_err(ast_ty.span,
"kind bounds can only be used on trait types"),
_ => { },
}
match a_def { match a_def {
ast::def_trait(_) => { ast::def_trait(_) => {
let path_str = path_to_str(path, tcx.sess.intr()); let path_str = path_to_str(path, tcx.sess.intr());

View file

@ -292,7 +292,7 @@ impl<'self> LookupContext<'self> {
ty_param(p) => { ty_param(p) => {
self.push_inherent_candidates_from_param(self_ty, p); self.push_inherent_candidates_from_param(self_ty, p);
} }
ty_trait(did, ref substs, store, _) => { ty_trait(did, ref substs, store, _, _) => {
self.push_inherent_candidates_from_trait( self.push_inherent_candidates_from_trait(
self_ty, did, substs, store); self_ty, did, substs, store);
self.push_inherent_impl_candidates_for_type(did); self.push_inherent_impl_candidates_for_type(did);

View file

@ -360,7 +360,7 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
// explaining how it goes about doing that. // explaining how it goes about doing that.
let target_ty = rcx.resolve_node_type(expr.id); let target_ty = rcx.resolve_node_type(expr.id);
match ty::get(target_ty).sty { match ty::get(target_ty).sty {
ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _) => { ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _, _) => {
let source_ty = rcx.fcx.expr_ty(source); let source_ty = rcx.fcx.expr_ty(source);
constrain_regions_in_type(rcx, trait_region, constrain_regions_in_type(rcx, trait_region,
expr.span, source_ty); expr.span, source_ty);

View file

@ -139,10 +139,11 @@ fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo,
let t = ty::mk_trait(tcx, let t = ty::mk_trait(tcx,
id, substs, id, substs,
ty::RegionTraitStore(ty::re_static), ty::RegionTraitStore(ty::re_static),
ast::m_imm); ast::m_imm,
ty::EmptyBuiltinBounds());
do fixup_ty(vcx, location_info, t, is_early).map |t_f| { do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
match ty::get(*t_f).sty { match ty::get(*t_f).sty {
ty::ty_trait(_, ref substs_f, _, _) => (/*bad*/copy *substs_f), ty::ty_trait(_, ref substs_f, _, _, _) => (/*bad*/copy *substs_f),
_ => fail!("t_f should be a trait") _ => fail!("t_f should be a trait")
} }
} }
@ -530,7 +531,9 @@ pub fn early_resolve_expr(ex: @ast::expr,
debug!("vtable resolution on expr %s", ex.repr(fcx.tcx())); debug!("vtable resolution on expr %s", ex.repr(fcx.tcx()));
let target_ty = fcx.expr_ty(ex); let target_ty = fcx.expr_ty(ex);
match ty::get(target_ty).sty { match ty::get(target_ty).sty {
ty::ty_trait(target_def_id, ref target_substs, store, target_mutbl) => { // Bounds of type's contents are not checked here, but in kind.rs.
ty::ty_trait(target_def_id, ref target_substs, store,
target_mutbl, _bounds) => {
fn mutability_allowed(a_mutbl: ast::mutability, fn mutability_allowed(a_mutbl: ast::mutability,
b_mutbl: ast::mutability) -> bool { b_mutbl: ast::mutability) -> bool {
a_mutbl == b_mutbl || a_mutbl == b_mutbl ||

View file

@ -114,7 +114,7 @@ pub fn type_is_defined_in_local_crate(original_type: t) -> bool {
do ty::walk_ty(original_type) |t| { do ty::walk_ty(original_type) |t| {
match get(t).sty { match get(t).sty {
ty_enum(def_id, _) | ty_enum(def_id, _) |
ty_trait(def_id, _, _, _) | ty_trait(def_id, _, _, _, _) |
ty_struct(def_id, _) => { ty_struct(def_id, _) => {
if def_id.crate == ast::local_crate { if def_id.crate == ast::local_crate {
found_nominal = true; found_nominal = true;
@ -140,7 +140,7 @@ pub fn get_base_type_def_id(inference_context: @mut InferCtxt,
match get(base_type).sty { match get(base_type).sty {
ty_enum(def_id, _) | ty_enum(def_id, _) |
ty_struct(def_id, _) | ty_struct(def_id, _) |
ty_trait(def_id, _, _, _) => { ty_trait(def_id, _, _, _, _) => {
return Some(def_id); return Some(def_id);
} }
_ => { _ => {
@ -753,7 +753,7 @@ impl CoherenceChecker {
pub fn ast_type_is_defined_in_local_crate(&self, original_type: @ast::Ty) pub fn ast_type_is_defined_in_local_crate(&self, original_type: @ast::Ty)
-> bool { -> bool {
match original_type.node { match original_type.node {
ty_path(_, path_id) => { ty_path(_, _, path_id) => {
match self.crate_context.tcx.def_map.get_copy(&path_id) { match self.crate_context.tcx.def_map.get_copy(&path_id) {
def_ty(def_id) | def_struct(def_id) => { def_ty(def_id) | def_struct(def_id) => {
if def_id.crate != local_crate { if def_id.crate != local_crate {

View file

@ -508,13 +508,15 @@ pub fn super_tys<C:Combine>(
} }
} }
(&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl), (&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl, a_bounds),
&ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl)) &ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl, b_bounds))
if a_id == b_id && a_mutbl == b_mutbl => { if a_id == b_id && a_mutbl == b_mutbl => {
let trait_def = ty::lookup_trait_def(tcx, a_id); let trait_def = ty::lookup_trait_def(tcx, a_id);
do this.substs(&trait_def.generics, a_substs, b_substs).chain |substs| { do this.substs(&trait_def.generics, a_substs, b_substs).chain |substs| {
do this.trait_stores(ty::terr_trait, a_store, b_store).chain |s| { do this.trait_stores(ty::terr_trait, a_store, b_store).chain |s| {
Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl)) do this.bounds(a_bounds, b_bounds).chain |bounds| {
Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl, bounds))
}
} }
} }
} }

View file

@ -717,10 +717,11 @@ impl InferCtxt {
trait_ref.def_id, trait_ref.def_id,
copy trait_ref.substs, copy trait_ref.substs,
ty::UniqTraitStore, ty::UniqTraitStore,
ast::m_imm); ast::m_imm,
ty::EmptyBuiltinBounds());
let dummy1 = self.resolve_type_vars_if_possible(dummy0); let dummy1 = self.resolve_type_vars_if_possible(dummy0);
match ty::get(dummy1).sty { match ty::get(dummy1).sty {
ty::ty_trait(ref def_id, ref substs, _, _) => { ty::ty_trait(ref def_id, ref substs, _, _, _) => {
ty::TraitRef {def_id: *def_id, ty::TraitRef {def_id: *def_id,
substs: copy *substs} substs: copy *substs}
} }

View file

@ -365,6 +365,8 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
s.push_str("fn"); s.push_str("fn");
s.push_str(cty.bounds.repr(cx));
push_sig_to_str(cx, &mut s, &cty.sig); push_sig_to_str(cx, &mut s, &cty.sig);
return s; return s;
@ -451,11 +453,13 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
let base = ast_map::path_to_str(path, cx.sess.intr()); let base = ast_map::path_to_str(path, cx.sess.intr());
parameterized(cx, base, substs.self_r, substs.tps) parameterized(cx, base, substs.self_r, substs.tps)
} }
ty_trait(did, ref substs, s, mutbl) => { ty_trait(did, ref substs, s, mutbl, ref bounds) => {
let path = ty::item_path(cx, did); let path = ty::item_path(cx, did);
let base = ast_map::path_to_str(path, cx.sess.intr()); let base = ast_map::path_to_str(path, cx.sess.intr());
let ty = parameterized(cx, base, substs.self_r, substs.tps); let ty = parameterized(cx, base, substs.self_r, substs.tps);
fmt!("%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty) let bound_str = bounds.repr(cx);
fmt!("%s%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
bound_str)
} }
ty_evec(ref mt, vs) => { ty_evec(ref mt, vs) => {
vstore_ty_to_str(cx, mt, vs) vstore_ty_to_str(cx, mt, vs)

View file

@ -797,7 +797,7 @@ pub enum ty_ {
ty_closure(@TyClosure), ty_closure(@TyClosure),
ty_bare_fn(@TyBareFn), ty_bare_fn(@TyBareFn),
ty_tup(~[@Ty]), ty_tup(~[@Ty]),
ty_path(@Path, node_id), ty_path(@Path, @OptVec<TyParamBound>, node_id),
ty_mac(mac), ty_mac(mac),
// ty_infer means the type should be inferred instead of it having been // ty_infer means the type should be inferred instead of it having been
// specified. This should only appear at the "top level" of a type and not // specified. This should only appear at the "top level" of a type and not

View file

@ -473,7 +473,7 @@ pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> {
visit_ty: |ty, (t, vt)| { visit_ty: |ty, (t, vt)| {
match ty.node { match ty.node {
ty_path(_, id) => vfn(id, copy t), ty_path(_, _, id) => vfn(id, copy t),
_ => { /* fall through */ } _ => { /* fall through */ }
} }
visit::visit_ty(ty, (t, vt)); visit::visit_ty(ty, (t, vt));

View file

@ -48,7 +48,7 @@ pub trait AstBuilder {
fn ty_mt(&self, ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt; fn ty_mt(&self, ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt;
fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty; fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty;
fn ty_path(&self, @ast::Path) -> @ast::Ty; fn ty_path(&self, @ast::Path, @OptVec<ast::TyParamBound>) -> @ast::Ty;
fn ty_ident(&self, span: span, idents: ast::ident) -> @ast::Ty; fn ty_ident(&self, span: span, idents: ast::ident) -> @ast::Ty;
fn ty_rptr(&self, span: span, fn ty_rptr(&self, span: span,
@ -267,14 +267,17 @@ impl AstBuilder for @ExtCtxt {
} }
} }
fn ty_path(&self, path: @ast::Path) -> @ast::Ty { fn ty_path(&self, path: @ast::Path, bounds: @OptVec<ast::TyParamBound>)
-> @ast::Ty {
self.ty(path.span, self.ty(path.span,
ast::ty_path(path, self.next_id())) ast::ty_path(path, bounds, self.next_id()))
} }
// Might need to take bounds as an argument in the future, if you ever want
// to generate a bounded existential trait type.
fn ty_ident(&self, span: span, ident: ast::ident) fn ty_ident(&self, span: span, ident: ast::ident)
-> @ast::Ty { -> @ast::Ty {
self.ty_path(self.path_ident(span, ident)) self.ty_path(self.path_ident(span, ident), @opt_vec::Empty)
} }
fn ty_rptr(&self, fn ty_rptr(&self,
@ -304,7 +307,8 @@ impl AstBuilder for @ExtCtxt {
self.ident_of("Option") self.ident_of("Option")
], ],
None, None,
~[ ty ])) ~[ ty ]),
@opt_vec::Empty)
} }
fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field { fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field {
@ -342,7 +346,7 @@ impl AstBuilder for @ExtCtxt {
fn ty_vars_global(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] { fn ty_vars_global(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] {
opt_vec::take_vec( opt_vec::take_vec(
ty_params.map(|p| self.ty_path( ty_params.map(|p| self.ty_path(
self.path_global(dummy_sp(), ~[p.ident])))) self.path_global(dummy_sp(), ~[p.ident]), @opt_vec::Empty)))
} }
fn strip_bounds(&self, generics: &Generics) -> Generics { fn strip_bounds(&self, generics: &Generics) -> Generics {

View file

@ -358,7 +358,8 @@ impl<'self> TraitDef<'self> {
// Create the type of `self`. // Create the type of `self`.
let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime, let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime,
opt_vec::take_vec(self_ty_params))); opt_vec::take_vec(self_ty_params)),
@opt_vec::Empty);
let doc_attr = cx.attribute( let doc_attr = cx.attribute(
span, span,

View file

@ -65,7 +65,7 @@ impl<'self> Path<'self> {
self_generics: &Generics) self_generics: &Generics)
-> @ast::Ty { -> @ast::Ty {
cx.ty_path(self.to_path(cx, span, cx.ty_path(self.to_path(cx, span,
self_ty, self_generics)) self_ty, self_generics), @opt_vec::Empty)
} }
pub fn to_path(&self, pub fn to_path(&self,
cx: @ExtCtxt, cx: @ExtCtxt,
@ -144,7 +144,8 @@ impl<'self> Ty<'self> {
} }
Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) } Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
Self => { Self => {
cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) cx.ty_path(self.to_path(cx, span, self_ty, self_generics),
@opt_vec::Empty)
} }
Tuple(ref fields) => { Tuple(ref fields) => {
let ty = if fields.is_empty() { let ty = if fields.is_empty() {

View file

@ -61,7 +61,7 @@ impl gen_send for message {
let pipe_ty = cx.ty_path( let pipe_ty = cx.ty_path(
path(~[this.data_name()], span) path(~[this.data_name()], span)
.add_tys(cx.ty_vars(&this.generics.ty_params))); .add_tys(cx.ty_vars(&this.generics.ty_params)), @opt_vec::Empty);
let args_ast = vec::append( let args_ast = vec::append(
~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)], ~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)],
args_ast); args_ast);
@ -117,7 +117,7 @@ impl gen_send for message {
let mut rty = cx.ty_path(path(~[next.data_name()], let mut rty = cx.ty_path(path(~[next.data_name()],
span) span)
.add_tys(copy next_state.tys)); .add_tys(copy next_state.tys), @opt_vec::Empty);
if try { if try {
rty = cx.ty_option(rty); rty = cx.ty_option(rty);
} }
@ -146,7 +146,7 @@ impl gen_send for message {
cx.ty_path( cx.ty_path(
path(~[this.data_name()], span) path(~[this.data_name()], span)
.add_tys(cx.ty_vars( .add_tys(cx.ty_vars(
&this.generics.ty_params))))], &this.generics.ty_params)), @opt_vec::Empty))],
args_ast); args_ast);
let message_args = if arg_names.len() == 0 { let message_args = if arg_names.len() == 0 {
@ -192,7 +192,7 @@ impl gen_send for message {
fn to_ty(&mut self, cx: @ExtCtxt) -> @ast::Ty { fn to_ty(&mut self, cx: @ExtCtxt) -> @ast::Ty {
cx.ty_path(path(~[cx.ident_of(self.name())], self.span()) cx.ty_path(path(~[cx.ident_of(self.name())], self.span())
.add_tys(cx.ty_vars(&self.get_generics().ty_params))) .add_tys(cx.ty_vars(&self.get_generics().ty_params)), @opt_vec::Empty)
} }
} }
@ -226,7 +226,7 @@ impl to_type_decls for state {
cx.ty_path( cx.ty_path(
path(~[cx.ident_of(dir), path(~[cx.ident_of(dir),
cx.ident_of(next_name)], span) cx.ident_of(next_name)], span)
.add_tys(copy next_state.tys))) .add_tys(copy next_state.tys), @opt_vec::Empty))
} }
None => tys None => tys
}; };
@ -279,7 +279,8 @@ impl to_type_decls for state {
self.data_name()], self.data_name()],
dummy_sp()) dummy_sp())
.add_tys(cx.ty_vars( .add_tys(cx.ty_vars(
&self.generics.ty_params))))), &self.generics.ty_params)), @opt_vec::Empty)),
@opt_vec::Empty),
cx.strip_bounds(&self.generics))); cx.strip_bounds(&self.generics)));
} }
else { else {
@ -298,8 +299,8 @@ impl to_type_decls for state {
self.data_name()], self.data_name()],
dummy_sp()) dummy_sp())
.add_tys(cx.ty_vars_global( .add_tys(cx.ty_vars_global(
&self.generics.ty_params))), &self.generics.ty_params)), @opt_vec::Empty),
self.proto.buffer_ty_path(cx)])), self.proto.buffer_ty_path(cx)]), @opt_vec::Empty),
cx.strip_bounds(&self.generics))); cx.strip_bounds(&self.generics)));
}; };
items items
@ -384,7 +385,7 @@ impl gen_init for protocol {
cx.ty_path(path(~[cx.ident_of("super"), cx.ty_path(path(~[cx.ident_of("super"),
cx.ident_of("__Buffer")], cx.ident_of("__Buffer")],
copy self.span) copy self.span)
.add_tys(cx.ty_vars_global(&params))) .add_tys(cx.ty_vars_global(&params)), @opt_vec::Empty)
} }
fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item { fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item {

View file

@ -15,6 +15,7 @@ use codemap::span;
use ext::base::ExtCtxt; use ext::base::ExtCtxt;
use ext::build::AstBuilder; use ext::build::AstBuilder;
use ext::pipes::ast_builder::{append_types, path}; use ext::pipes::ast_builder::{append_types, path};
use opt_vec;
#[deriving(Eq)] #[deriving(Eq)]
pub enum direction { send, recv } pub enum direction { send, recv }
@ -101,7 +102,7 @@ impl state_ {
pub fn to_ty(&self, cx: @ExtCtxt) -> @ast::Ty { pub fn to_ty(&self, cx: @ExtCtxt) -> @ast::Ty {
cx.ty_path cx.ty_path
(path(~[cx.ident_of(self.name)],self.span).add_tys( (path(~[cx.ident_of(self.name)],self.span).add_tys(
cx.ty_vars(&self.generics.ty_params))) cx.ty_vars(&self.generics.ty_params)), @opt_vec::Empty)
} }
/// Iterate over the states that can be reached in one message /// Iterate over the states that can be reached in one message

View file

@ -680,7 +680,9 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
}) })
} }
ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(*ty))), ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(*ty))),
ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)), ty_path(path, bounds, id) =>
ty_path(fld.fold_path(path),
@bounds.map(|x| fold_ty_param_bound(x, fld)), fld.new_id(id)),
ty_fixed_length_vec(ref mt, e) => { ty_fixed_length_vec(ref mt, e) => {
ty_fixed_length_vec( ty_fixed_length_vec(
fold_mt(mt, fld), fold_mt(mt, fld),

View file

@ -494,7 +494,7 @@ mod test {
idents:~[str_to_ident("int")], idents:~[str_to_ident("int")],
rp: None, rp: None,
types: ~[]}, types: ~[]},
2), @opt_vec::Empty, 2),
span:sp(4,7)}, span:sp(4,7)},
pat: @ast::pat{id:1, pat: @ast::pat{id:1,
node: ast::pat_ident(ast::bind_infer, node: ast::pat_ident(ast::bind_infer,
@ -530,7 +530,7 @@ mod test {
idents:~[str_to_ident("int")], idents:~[str_to_ident("int")],
rp: None, rp: None,
types: ~[]}, types: ~[]},
2), @opt_vec::Empty, 2),
span:sp(10,13)}, span:sp(10,13)},
pat: @ast::pat{id:1, // fixme pat: @ast::pat{id:1, // fixme
node: ast::pat_ident( node: ast::pat_ident(

View file

@ -46,7 +46,6 @@ pub enum ObsoleteSyntax {
ObsoleteUnsafeBlock, ObsoleteUnsafeBlock,
ObsoleteUnenforcedBound, ObsoleteUnenforcedBound,
ObsoleteImplSyntax, ObsoleteImplSyntax,
ObsoleteTraitBoundSeparator,
ObsoleteMutOwnedPointer, ObsoleteMutOwnedPointer,
ObsoleteMutVector, ObsoleteMutVector,
ObsoleteImplVisibility, ObsoleteImplVisibility,
@ -143,10 +142,6 @@ impl Parser {
"colon-separated impl syntax", "colon-separated impl syntax",
"write `impl Trait for Type`" "write `impl Trait for Type`"
), ),
ObsoleteTraitBoundSeparator => (
"space-separated trait bounds",
"write `+` between trait bounds"
),
ObsoleteMutOwnedPointer => ( ObsoleteMutOwnedPointer => (
"const or mutable owned pointer", "const or mutable owned pointer",
"mutability inherits through `~` pointers; place the `~` box "mutability inherits through `~` pointers; place the `~` box

View file

@ -75,7 +75,7 @@ use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap}; use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap};
use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds}; use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax}; use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer}; use parse::obsolete::{ObsoleteMutOwnedPointer};
use parse::obsolete::{ObsoleteMutVector, ObsoleteImplVisibility}; use parse::obsolete::{ObsoleteMutVector, ObsoleteImplVisibility};
use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern}; use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern};
use parse::obsolete::{ObsoletePostFnTySigil}; use parse::obsolete::{ObsoletePostFnTySigil};
@ -710,8 +710,8 @@ impl Parser {
} else if *self.token == token::MOD_SEP } else if *self.token == token::MOD_SEP
|| is_ident_or_path(self.token) { || is_ident_or_path(self.token) {
// NAMED TYPE // NAMED TYPE
let path = self.parse_path_with_tps(false); let (path, bounds) = self.parse_type_path();
ty_path(path, self.get_id()) ty_path(path, @bounds, self.get_id())
} else { } else {
self.fatal(fmt!("expected type, found token %?", self.fatal(fmt!("expected type, found token %?",
*self.token)); *self.token));
@ -974,10 +974,8 @@ impl Parser {
types: ~[] } types: ~[] }
} }
// parse a path optionally with type parameters. If 'colons' pub fn parse_bounded_path_with_tps(&self, colons: bool,
// is true, then type parameters must be preceded by colons, before_tps: Option<&fn()>) -> @ast::Path {
// as in a::t::<t1,t2>
pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
debug!("parse_path_with_tps(colons=%b)", colons); debug!("parse_path_with_tps(colons=%b)", colons);
maybe_whole!(self, nt_path); maybe_whole!(self, nt_path);
@ -987,6 +985,10 @@ impl Parser {
return path; return path;
} }
// If the path might have bounds on it, they should be parsed before
// the parameters, e.g. module::TraitName:B1+B2<T>
before_tps.map_consume(|callback| callback());
// Parse the (obsolete) trailing region parameter, if any, which will // Parse the (obsolete) trailing region parameter, if any, which will
// be written "foo/&x" // be written "foo/&x"
let rp_slash = { let rp_slash = {
@ -1038,6 +1040,25 @@ impl Parser {
.. copy *path } .. copy *path }
} }
// parse a path optionally with type parameters. If 'colons'
// is true, then type parameters must be preceded by colons,
// as in a::t::<t1,t2>
pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
self.parse_bounded_path_with_tps(colons, None)
}
// Like the above, but can also parse kind bounds in the case of a
// path to be used as a type that might be a trait.
pub fn parse_type_path(&self) -> (@ast::Path, OptVec<TyParamBound>) {
let mut bounds = opt_vec::Empty;
let path = self.parse_bounded_path_with_tps(false, Some(|| {
// Note: this closure might not even get called in the case of a
// macro-generated path. But that's the macro parser's job.
bounds = self.parse_optional_ty_param_bounds();
}));
(path, bounds)
}
/// parses 0 or 1 lifetime /// parses 0 or 1 lifetime
pub fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> { pub fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> {
match *self.token { match *self.token {
@ -2847,16 +2868,6 @@ impl Parser {
spanned(lo, hi, bloc) spanned(lo, hi, bloc)
} }
fn mk_ty_path(&self, i: ident) -> @Ty {
@Ty {
id: self.get_id(),
node: ty_path(
ident_to_path(*self.last_span, i),
self.get_id()),
span: *self.last_span,
}
}
fn parse_optional_purity(&self) -> ast::purity { fn parse_optional_purity(&self) -> ast::purity {
if self.eat_keyword(keywords::Pure) { if self.eat_keyword(keywords::Pure) {
self.obsolete(*self.last_span, ObsoletePurity); self.obsolete(*self.last_span, ObsoletePurity);
@ -2921,13 +2932,8 @@ impl Parser {
_ => break, _ => break,
} }
if self.eat(&token::BINOP(token::PLUS)) { if !self.eat(&token::BINOP(token::PLUS)) {
loop; break;
}
if is_ident_or_path(self.token) {
self.obsolete(*self.span,
ObsoleteTraitBoundSeparator);
} }
} }
@ -3284,14 +3290,19 @@ impl Parser {
let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) { let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
// New-style trait. Reinterpret the type as a trait. // New-style trait. Reinterpret the type as a trait.
let opt_trait_ref = match ty.node { let opt_trait_ref = match ty.node {
ty_path(path, node_id) => { ty_path(path, @opt_vec::Empty, node_id) => {
Some(@trait_ref { Some(@trait_ref {
path: path, path: path,
ref_id: node_id ref_id: node_id
}) })
} }
ty_path(*) => {
self.span_err(ty.span,
"bounded traits are only valid in type position");
None
}
_ => { _ => {
self.span_err(*self.span, "not a trait"); self.span_err(ty.span, "not a trait");
None None
} }
}; };

View file

@ -422,7 +422,7 @@ pub fn print_type(s: @ps, ty: @ast::Ty) {
f.purity, f.onceness, &f.decl, None, f.purity, f.onceness, &f.decl, None,
Some(&generics), None); Some(&generics), None);
} }
ast::ty_path(path, _) => print_path(s, path, false), ast::ty_path(path, bounds, _) => print_bounded_path(s, path, bounds),
ast::ty_fixed_length_vec(ref mt, v) => { ast::ty_fixed_length_vec(ref mt, v) => {
word(s.s, "["); word(s.s, "[");
match mt.mutbl { match mt.mutbl {
@ -1483,7 +1483,8 @@ pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) {
print_expr(s, coll); print_expr(s, coll);
} }
pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) { fn print_path_(s: @ps, path: @ast::Path, colons_before_params: bool,
opt_bounds: Option<@OptVec<ast::TyParamBound>>) {
maybe_print_comment(s, path.span.lo); maybe_print_comment(s, path.span.lo);
if path.global { word(s.s, "::"); } if path.global { word(s.s, "::"); }
let mut first = true; let mut first = true;
@ -1491,6 +1492,9 @@ pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
if first { first = false; } else { word(s.s, "::"); } if first { first = false; } else { word(s.s, "::"); }
print_ident(s, *id); print_ident(s, *id);
} }
do opt_bounds.map_consume |bounds| {
print_bounds(s, bounds);
};
if path.rp.is_some() || !path.types.is_empty() { if path.rp.is_some() || !path.types.is_empty() {
if colons_before_params { word(s.s, "::"); } if colons_before_params { word(s.s, "::"); }
@ -1511,6 +1515,15 @@ pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
} }
} }
pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
print_path_(s, path, colons_before_params, None)
}
pub fn print_bounded_path(s: @ps, path: @ast::Path,
bounds: @OptVec<ast::TyParamBound>) {
print_path_(s, path, false, Some(bounds))
}
pub fn print_irrefutable_pat(s: @ps, pat: @ast::pat) { pub fn print_irrefutable_pat(s: @ps, pat: @ast::pat) {
print_pat(s, pat, false) print_pat(s, pat, false)
} }

View file

@ -247,13 +247,17 @@ pub fn visit_ty<E: Copy>(t: @Ty, (e, v): (E, vt<E>)) {
}, },
ty_closure(ref f) => { ty_closure(ref f) => {
for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); } for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
(v.visit_ty)(f.decl.output, (e, v)); (v.visit_ty)(f.decl.output, (copy e, v));
visit_ty_param_bounds(&f.bounds, (e, v));
}, },
ty_bare_fn(ref f) => { ty_bare_fn(ref f) => {
for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); } for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
(v.visit_ty)(f.decl.output, (e, v)); (v.visit_ty)(f.decl.output, (e, v));
}, },
ty_path(p, _) => visit_path(p, (e, v)), ty_path(p, bounds, _) => {
visit_path(p, (copy e, v));
visit_ty_param_bounds(bounds, (e, v));
},
ty_fixed_length_vec(ref mt, ex) => { ty_fixed_length_vec(ref mt, ex) => {
(v.visit_ty)(mt.ty, (copy e, v)); (v.visit_ty)(mt.ty, (copy e, v));
(v.visit_expr)(ex, (copy e, v)); (v.visit_expr)(ex, (copy e, v));
@ -328,7 +332,7 @@ pub fn visit_foreign_item<E: Copy>(ni: @foreign_item, (e, v): (E, vt<E>)) {
} }
} }
pub fn visit_ty_param_bounds<E: Copy>(bounds: @OptVec<TyParamBound>, pub fn visit_ty_param_bounds<E: Copy>(bounds: &OptVec<TyParamBound>,
(e, v): (E, vt<E>)) { (e, v): (E, vt<E>)) {
for bounds.each |bound| { for bounds.each |bound| {
match *bound { match *bound {