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_attributes(ebml_w, item.attrs);
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,
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 store = parse_trait_store(st);
let mt = parse_mutability(st);
let bounds = parse_bounds(st, conv);
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' => {
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);
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((cx.ds)(def));
w.write_char('|');
enc_substs(w, cx, substs);
enc_trait_store(w, cx, store);
enc_mutability(w, mt);
let bounds = ty::ParamBounds {builtin_bounds: bounds,
trait_bounds: ~[]};
enc_bounds(w, cx, &bounds);
w.write_char(']');
}
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 {
// Yes, it's a destructor.
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(
&path_node_id);
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>)) {
match aty.node {
ty_path(_, id) => {
ty_path(_, _, id) => {
let r = cx.tcx.node_type_substs.find(&id);
for r.iter().advance |ts| {
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) {
let target_ty = ty::expr_ty(cx.tcx, target);
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);
if !ty::type_is_owned(cx.tcx, source_ty) {
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 );
for vec::each(vec::append_one(tys, decl.output)) |ty| {
match ty.node {
ast::ty_path(_, id) => {
ast::ty_path(_, _, id) => {
match cx.tcx.def_map.get_copy(&id) {
ast::def_prim_ty(ast::ty_int(ast::ty_i)) => {
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
// that as a direct dependency.
match ty.node {
ast::ty_path(path, id) => {
ast::ty_path(path, _bounds, id) => {
match cx.def_map.find(&id) {
Some(&ast::def_ty(did)) |
Some(&ast::def_trait(did)) |
@ -840,7 +840,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
visit_mt(mt, (cx, visitor));
}
ast::ty_path(path, _) => {
ast::ty_path(path, _bounds, _) => {
// type parameters are---for now, anyway---always invariant
do cx.with_ambient_variance(rv_invariant) {
for path.types.iter().advance |tp| {

View File

@ -1250,7 +1250,7 @@ impl Resolver {
// If there are static methods, then create the module
// and add them.
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 => {
let name = path_to_ident(path);
@ -4120,7 +4120,7 @@ impl Resolver {
// Like path expressions, the interpretation of path types depends
// 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
// scopes looking for it.
let mut result_def = None;
@ -4179,6 +4179,10 @@ impl Resolver {
self.idents_to_str(path.idents)));
}
}
for bounds.each |bound| {
self.resolve_type_parameter_bound(bound, visitor);
}
}
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");
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");
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, _) => {
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,
store);
}

View File

@ -486,13 +486,13 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
ty::ty_closure(_) => {
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 = Load(bcx, llbox_ptr);
decr_refcnt_maybe_free(bcx, llbox, Some(llbox_ptr),
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]);
// Only drop the value when it is non-null
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(_) => {
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]));
incr_refcnt_of_boxed(bcx, llbox);
bcx
}
ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
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) => {
Some(normalized_closure_ty(tcx, fty.sigil))
}
ty::ty_trait(_, _, ref store, _) => {
ty::ty_trait(_, _, ref store, _, _) => {
let sigil = match *store {
ty::UniqTraitStore => ast::OwnedSigil,
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 {
ty_path(p, p_id) => {
ty_path(p, _bounds, 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
// to do

View File

@ -335,7 +335,7 @@ impl Reflector {
}
// Miscallaneous extra types
ty::ty_trait(_, _, _, _) => self.leaf(~"trait"),
ty::ty_trait(_, _, _, _, _) => self.leaf(~"trait"),
ty::ty_infer(_) => self.leaf(~"infer"),
ty::ty_err => self.leaf(~"err"),
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_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_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);
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_tup(*) => {
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_ptr(_) |
ty::ty_rptr(_, _) |
ty::ty_trait(_, _, _, _) => false,
ty::ty_trait(*) => false,
ty::ty_enum(did, ref substs) => {
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.onceness.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_bare_fn(BareFnTy),
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_tup(~[t]),
@ -1046,7 +1047,7 @@ fn mk_t(cx: ctxt, st: sty) -> t {
&ty_infer(_) => flags |= needs_infer as uint,
&ty_self(_) => flags |= has_self as uint,
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) |
&ty_trait(_, ref substs, _, _) => {
&ty_trait(_, ref substs, _, _, _) => {
flags |= sflags(substs);
}
&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,
substs: substs,
store: TraitStore,
mutability: ast::mutability)
mutability: ast::mutability,
bounds: BuiltinBounds)
-> t {
// 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 {
@ -1319,7 +1321,7 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) {
maybe_walk_ty(tm.ty, f);
}
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); }
}
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, fold_substs(substs, fldop))
}
ty_trait(did, ref substs, st, mutbl) => {
ty_trait(did, fold_substs(substs, fldop), st, mutbl)
ty_trait(did, ref substs, st, mutbl, bounds) => {
ty_trait(did, fold_substs(substs, fldop), st, mutbl, bounds)
}
ty_tup(ref ts) => {
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::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt))
}
ty_trait(def_id, ref substs, st, mutbl) => {
ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl)
ty_trait(def_id, ref substs, st, mutbl, bounds) => {
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::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)))
}
ty_trait(_, _, UniqTraitStore, _) => {
ty_trait(_, _, UniqTraitStore, _, _bounds) => {
TC_OWNED_CLOSURE
}
ty_trait(_, _, BoxTraitStore, mutbl) => {
ty_trait(_, _, BoxTraitStore, mutbl, _bounds) => {
match mutbl {
ast::m_mutbl => TC_MANAGED + TC_MUTABLE,
_ => TC_MANAGED
}
}
ty_trait(_, _, RegionTraitStore(r), mutbl) => {
ty_trait(_, _, RegionTraitStore(r), mutbl, _bounds) => {
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
}
ty_trait(_, _, _, _) => {
ty_trait(_, _, _, _, _) => {
false
}
@ -2500,7 +2506,7 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
ty_box(_) | ty_uniq(_) | ty_closure(_) |
ty_estr(vstore_uniq) | ty_estr(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
ty_enum(did, ref substs) => {
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_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) &&
did.iter_bytes(lsb0, f) &&
substs.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),
@ -3440,7 +3447,7 @@ pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
ty_rptr(_, _) => ~"&-ptr",
ty_bare_fn(_) => ~"extern 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_tup(_) => ~"tuple",
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> {
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
}
}
@ -4454,5 +4461,6 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name));
let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name);
(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);
}
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) {
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);
@ -300,11 +303,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
ty::BoxTraitStore
}
};
let bounds = conv_builtin_bounds(this.tcx(), bounds);
return ty::mk_trait(tcx,
result.def_id,
copy result.substs,
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);
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) {
None => tcx.sess.span_fatal(
ast_ty.span, fmt!("unbound path %s",
path_to_str(path, tcx.sess.intr()))),
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 {
ast::def_trait(_) => {
let path_str = path_to_str(path, tcx.sess.intr());

View File

@ -292,7 +292,7 @@ impl<'self> LookupContext<'self> {
ty_param(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_ty, did, substs, store);
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.
let target_ty = rcx.resolve_node_type(expr.id);
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);
constrain_regions_in_type(rcx, trait_region,
expr.span, source_ty);

View File

@ -139,10 +139,11 @@ fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo,
let t = ty::mk_trait(tcx,
id, substs,
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| {
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")
}
}
@ -530,7 +531,9 @@ pub fn early_resolve_expr(ex: @ast::expr,
debug!("vtable resolution on expr %s", ex.repr(fcx.tcx()));
let target_ty = fcx.expr_ty(ex);
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,
b_mutbl: ast::mutability) -> bool {
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| {
match get(t).sty {
ty_enum(def_id, _) |
ty_trait(def_id, _, _, _) |
ty_trait(def_id, _, _, _, _) |
ty_struct(def_id, _) => {
if def_id.crate == ast::local_crate {
found_nominal = true;
@ -140,7 +140,7 @@ pub fn get_base_type_def_id(inference_context: @mut InferCtxt,
match get(base_type).sty {
ty_enum(def_id, _) |
ty_struct(def_id, _) |
ty_trait(def_id, _, _, _) => {
ty_trait(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)
-> bool {
match original_type.node {
ty_path(_, path_id) => {
ty_path(_, _, path_id) => {
match self.crate_context.tcx.def_map.get_copy(&path_id) {
def_ty(def_id) | def_struct(def_id) => {
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(b_id, ref b_substs, b_store, b_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, b_bounds))
if a_id == b_id && a_mutbl == b_mutbl => {
let trait_def = ty::lookup_trait_def(tcx, a_id);
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| {
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,
copy trait_ref.substs,
ty::UniqTraitStore,
ast::m_imm);
ast::m_imm,
ty::EmptyBuiltinBounds());
let dummy1 = self.resolve_type_vars_if_possible(dummy0);
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,
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(cty.bounds.repr(cx));
push_sig_to_str(cx, &mut s, &cty.sig);
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());
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 base = ast_map::path_to_str(path, cx.sess.intr());
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) => {
vstore_ty_to_str(cx, mt, vs)

View File

@ -797,7 +797,7 @@ pub enum ty_ {
ty_closure(@TyClosure),
ty_bare_fn(@TyBareFn),
ty_tup(~[@Ty]),
ty_path(@Path, node_id),
ty_path(@Path, @OptVec<TyParamBound>, node_id),
ty_mac(mac),
// 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

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)| {
match ty.node {
ty_path(_, id) => vfn(id, copy t),
ty_path(_, _, id) => vfn(id, copy t),
_ => { /* fall through */ }
}
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(&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_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,
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)
-> @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,
@ -304,7 +307,8 @@ impl AstBuilder for @ExtCtxt {
self.ident_of("Option")
],
None,
~[ ty ]))
~[ ty ]),
@opt_vec::Empty)
}
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] {
opt_vec::take_vec(
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 {

View File

@ -358,7 +358,8 @@ impl<'self> TraitDef<'self> {
// Create the type of `self`.
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(
span,

View File

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

View File

@ -61,7 +61,7 @@ impl gen_send for message {
let pipe_ty = cx.ty_path(
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(
~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)],
args_ast);
@ -117,7 +117,7 @@ impl gen_send for message {
let mut rty = cx.ty_path(path(~[next.data_name()],
span)
.add_tys(copy next_state.tys));
.add_tys(copy next_state.tys), @opt_vec::Empty);
if try {
rty = cx.ty_option(rty);
}
@ -146,7 +146,7 @@ impl gen_send for message {
cx.ty_path(
path(~[this.data_name()], span)
.add_tys(cx.ty_vars(
&this.generics.ty_params))))],
&this.generics.ty_params)), @opt_vec::Empty))],
args_ast);
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 {
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(
path(~[cx.ident_of(dir),
cx.ident_of(next_name)], span)
.add_tys(copy next_state.tys)))
.add_tys(copy next_state.tys), @opt_vec::Empty))
}
None => tys
};
@ -279,7 +279,8 @@ impl to_type_decls for state {
self.data_name()],
dummy_sp())
.add_tys(cx.ty_vars(
&self.generics.ty_params))))),
&self.generics.ty_params)), @opt_vec::Empty)),
@opt_vec::Empty),
cx.strip_bounds(&self.generics)));
}
else {
@ -298,8 +299,8 @@ impl to_type_decls for state {
self.data_name()],
dummy_sp())
.add_tys(cx.ty_vars_global(
&self.generics.ty_params))),
self.proto.buffer_ty_path(cx)])),
&self.generics.ty_params)), @opt_vec::Empty),
self.proto.buffer_ty_path(cx)]), @opt_vec::Empty),
cx.strip_bounds(&self.generics)));
};
items
@ -384,7 +385,7 @@ impl gen_init for protocol {
cx.ty_path(path(~[cx.ident_of("super"),
cx.ident_of("__Buffer")],
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 {

View File

@ -15,6 +15,7 @@ use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::pipes::ast_builder::{append_types, path};
use opt_vec;
#[deriving(Eq)]
pub enum direction { send, recv }
@ -101,7 +102,7 @@ impl state_ {
pub fn to_ty(&self, cx: @ExtCtxt) -> @ast::Ty {
cx.ty_path
(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

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_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(
fold_mt(mt, fld),

View File

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

View File

@ -46,7 +46,6 @@ pub enum ObsoleteSyntax {
ObsoleteUnsafeBlock,
ObsoleteUnenforcedBound,
ObsoleteImplSyntax,
ObsoleteTraitBoundSeparator,
ObsoleteMutOwnedPointer,
ObsoleteMutVector,
ObsoleteImplVisibility,
@ -143,10 +142,6 @@ impl Parser {
"colon-separated impl syntax",
"write `impl Trait for Type`"
),
ObsoleteTraitBoundSeparator => (
"space-separated trait bounds",
"write `+` between trait bounds"
),
ObsoleteMutOwnedPointer => (
"const or mutable owned pointer",
"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::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
use parse::obsolete::{ObsoleteMutOwnedPointer};
use parse::obsolete::{ObsoleteMutVector, ObsoleteImplVisibility};
use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern};
use parse::obsolete::{ObsoletePostFnTySigil};
@ -710,8 +710,8 @@ impl Parser {
} else if *self.token == token::MOD_SEP
|| is_ident_or_path(self.token) {
// NAMED TYPE
let path = self.parse_path_with_tps(false);
ty_path(path, self.get_id())
let (path, bounds) = self.parse_type_path();
ty_path(path, @bounds, self.get_id())
} else {
self.fatal(fmt!("expected type, found token %?",
*self.token));
@ -974,10 +974,8 @@ impl Parser {
types: ~[] }
}
// 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 {
pub fn parse_bounded_path_with_tps(&self, colons: bool,
before_tps: Option<&fn()>) -> @ast::Path {
debug!("parse_path_with_tps(colons=%b)", colons);
maybe_whole!(self, nt_path);
@ -987,6 +985,10 @@ impl Parser {
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
// be written "foo/&x"
let rp_slash = {
@ -1038,6 +1040,25 @@ impl Parser {
.. 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
pub fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> {
match *self.token {
@ -2847,16 +2868,6 @@ impl Parser {
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 {
if self.eat_keyword(keywords::Pure) {
self.obsolete(*self.last_span, ObsoletePurity);
@ -2921,13 +2932,8 @@ impl Parser {
_ => break,
}
if self.eat(&token::BINOP(token::PLUS)) {
loop;
}
if is_ident_or_path(self.token) {
self.obsolete(*self.span,
ObsoleteTraitBoundSeparator);
if !self.eat(&token::BINOP(token::PLUS)) {
break;
}
}
@ -3284,14 +3290,19 @@ impl Parser {
let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
// New-style trait. Reinterpret the type as a trait.
let opt_trait_ref = match ty.node {
ty_path(path, node_id) => {
ty_path(path, @opt_vec::Empty, node_id) => {
Some(@trait_ref {
path: path,
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
}
};

View File

@ -422,7 +422,7 @@ pub fn print_type(s: @ps, ty: @ast::Ty) {
f.purity, f.onceness, &f.decl, 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) => {
word(s.s, "[");
match mt.mutbl {
@ -1483,7 +1483,8 @@ pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) {
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);
if path.global { word(s.s, "::"); }
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, "::"); }
print_ident(s, *id);
}
do opt_bounds.map_consume |bounds| {
print_bounds(s, bounds);
};
if path.rp.is_some() || !path.types.is_empty() {
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) {
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) => {
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) => {
for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy 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) => {
(v.visit_ty)(mt.ty, (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>)) {
for bounds.each |bound| {
match *bound {