auto merge of #7314 : bblum/rust/trait-bounds2, r=nikomatsakis
Fixed a merge conflict, some tests, some bitrotting, etc., from #7248.
This commit is contained in:
commit
f82756180b
@ -2,7 +2,7 @@
|
||||
" Language: Rust
|
||||
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
|
||||
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
|
||||
" Last Change: 2012 Dec 25
|
||||
" Last Change: 2012 Jun 14
|
||||
|
||||
if version < 600
|
||||
syntax clear
|
||||
@ -13,13 +13,16 @@ endif
|
||||
syn keyword rustConditional match if else
|
||||
syn keyword rustOperator as
|
||||
|
||||
syn match rustAssert "\<assert\(\w\)*!"
|
||||
syn match rustFail "\<fail\(\w\)*!"
|
||||
syn keyword rustKeyword break copy do drop extern
|
||||
syn keyword rustKeyword for if impl let log
|
||||
syn keyword rustKeyword copy do extern
|
||||
syn keyword rustKeyword for impl let log
|
||||
syn keyword rustKeyword loop mod once priv pub
|
||||
syn keyword rustKeyword return
|
||||
syn keyword rustKeyword unsafe use while
|
||||
syn keyword rustKeyword unsafe while
|
||||
syn keyword rustKeyword use nextgroup=rustModPath skipwhite
|
||||
" FIXME: Scoped impl's name is also fallen in this category
|
||||
syn keyword rustKeyword mod trait struct enum type nextgroup=rustIdentifier skipwhite
|
||||
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite
|
||||
@ -45,7 +48,8 @@ syn keyword rustType c_longlong c_ulonglong intptr_t uintptr_t
|
||||
syn keyword rustType off_t dev_t ino_t pid_t mode_t ssize_t
|
||||
|
||||
syn keyword rustTrait Const Copy Send Owned Sized " inherent traits
|
||||
syn keyword rustTrait Eq Ord Num Ptr
|
||||
syn keyword rustTrait Clone Decodable Encodable IterBytes Rand ToStr
|
||||
syn keyword rustTrait Eq Ord TotalEq TotalOrd Num Ptr
|
||||
syn keyword rustTrait Drop Add Sub Mul Quot Rem Neg BitAnd BitOr
|
||||
syn keyword rustTrait BitXor Shl Shr Index
|
||||
|
||||
@ -72,19 +76,21 @@ syn keyword rustConstant STDIN_FILENO STDOUT_FILENO STDERR_FILENO
|
||||
" If foo::bar changes to foo.bar, change this ("::" to "\.").
|
||||
" If foo::bar changes to Foo::bar, change this (first "\w" to "\u").
|
||||
syn match rustModPath "\w\(\w\)*::[^<]"he=e-3,me=e-3
|
||||
syn match rustModPath "\w\(\w\)*" contained " only for 'use path;'
|
||||
syn match rustModPathSep "::"
|
||||
|
||||
syn match rustFuncCall "\w\(\w\)*("he=e-1,me=e-1
|
||||
syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>();
|
||||
|
||||
syn match rustMacro '\w\(\w\)*!'
|
||||
syn match rustMacro '#\w\(\w\)*'
|
||||
syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustFail
|
||||
syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustFail
|
||||
|
||||
syn match rustFormat display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlLjzt]\|ll\|hh\)\=\([aAbdiuoxXDOUfFeEgGcCsSpn?]\|\[\^\=.[^]]*\]\)" contained
|
||||
syn match rustFormat display "%%" contained
|
||||
syn region rustString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=rustTodo,rustFormat
|
||||
|
||||
syn region rustAttribute start="#\[" end="\]" contains=rustString
|
||||
syn region rustAttribute start="#\[" end="\]" contains=rustString,rustDeriving
|
||||
syn region rustDeriving start="deriving(" end=")" contains=rustTrait
|
||||
|
||||
" Number literals
|
||||
syn match rustNumber display "\<[0-9][0-9_]*\>"
|
||||
@ -143,11 +149,17 @@ hi def link rustMacro Macro
|
||||
hi def link rustType Type
|
||||
hi def link rustTodo Todo
|
||||
hi def link rustAttribute PreProc
|
||||
hi def link rustDeriving PreProc
|
||||
hi def link rustStorage StorageClass
|
||||
hi def link rustLifetime Special
|
||||
|
||||
" Other Suggestions:
|
||||
" hi rustAttribute ctermfg=cyan
|
||||
" hi rustDeriving ctermfg=cyan
|
||||
" hi rustAssert ctermfg=yellow
|
||||
" hi rustFail ctermfg=red
|
||||
" hi rustMacro ctermfg=magenta
|
||||
" hi rustModPathSep ctermfg=grey
|
||||
|
||||
syn sync minlines=200
|
||||
syn sync maxlines=500
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
@ -81,8 +81,6 @@ pub fn check_crate(tcx: ty::ctxt,
|
||||
tcx.sess.abort_if_errors();
|
||||
}
|
||||
|
||||
type check_fn = @fn(Context, @freevar_entry);
|
||||
|
||||
fn check_struct_safe_for_destructor(cx: Context,
|
||||
span: span,
|
||||
struct_did: def_id) {
|
||||
@ -129,7 +127,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 =
|
||||
@ -162,30 +161,43 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
|
||||
// Yields the appropriate function to check the kind of closed over
|
||||
// variables. `id` is the node_id for some expression that creates the
|
||||
// closure.
|
||||
fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) {
|
||||
fn check_for_uniq(cx: Context, fv: @freevar_entry) {
|
||||
fn with_appropriate_checker(cx: Context, id: node_id,
|
||||
b: &fn(checker: &fn(Context, @freevar_entry))) {
|
||||
fn check_for_uniq(cx: Context, fv: @freevar_entry, bounds: ty::BuiltinBounds) {
|
||||
// all captured data must be owned, regardless of whether it is
|
||||
// moved in or copied in.
|
||||
let id = ast_util::def_id_of_def(fv.def).node;
|
||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
||||
|
||||
// FIXME(#3569): Once closure capabilities are restricted based on their
|
||||
// incoming bounds, make this check conditional based on the bounds.
|
||||
if !check_owned(cx, var_t, fv.span) { return; }
|
||||
|
||||
// check that only immutable variables are implicitly copied in
|
||||
check_imm_free_var(cx, fv.def, fv.span);
|
||||
|
||||
check_freevar_bounds(cx, fv.span, var_t, bounds);
|
||||
}
|
||||
|
||||
fn check_for_box(cx: Context, fv: @freevar_entry) {
|
||||
fn check_for_box(cx: Context, fv: @freevar_entry, bounds: ty::BuiltinBounds) {
|
||||
// all captured data must be owned
|
||||
let id = ast_util::def_id_of_def(fv.def).node;
|
||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
||||
|
||||
// FIXME(#3569): Once closure capabilities are restricted based on their
|
||||
// incoming bounds, make this check conditional based on the bounds.
|
||||
if !check_durable(cx.tcx, var_t, fv.span) { return; }
|
||||
|
||||
// check that only immutable variables are implicitly copied in
|
||||
check_imm_free_var(cx, fv.def, fv.span);
|
||||
|
||||
check_freevar_bounds(cx, fv.span, var_t, bounds);
|
||||
}
|
||||
|
||||
fn check_for_block(_cx: Context, _fv: @freevar_entry) {
|
||||
// no restrictions
|
||||
fn check_for_block(cx: Context, fv: @freevar_entry, bounds: ty::BuiltinBounds) {
|
||||
let id = ast_util::def_id_of_def(fv.def).node;
|
||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
||||
check_freevar_bounds(cx, fv.span, var_t, bounds);
|
||||
}
|
||||
|
||||
fn check_for_bare(cx: Context, fv: @freevar_entry) {
|
||||
@ -196,14 +208,14 @@ fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) {
|
||||
|
||||
let fty = ty::node_id_to_type(cx.tcx, id);
|
||||
match ty::get(fty).sty {
|
||||
ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, _}) => {
|
||||
b(check_for_uniq)
|
||||
ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, bounds: bounds, _}) => {
|
||||
b(|cx, fv| check_for_uniq(cx, fv, bounds))
|
||||
}
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, _}) => {
|
||||
b(check_for_box)
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, bounds: bounds, _}) => {
|
||||
b(|cx, fv| check_for_box(cx, fv, bounds))
|
||||
}
|
||||
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, _}) => {
|
||||
b(check_for_block)
|
||||
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, bounds: bounds, _}) => {
|
||||
b(|cx, fv| check_for_block(cx, fv, bounds))
|
||||
}
|
||||
ty::ty_bare_fn(_) => {
|
||||
b(check_for_bare)
|
||||
@ -271,7 +283,7 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
|
||||
type_param_defs.repr(cx.tcx));
|
||||
}
|
||||
for ts.iter().zip(type_param_defs.iter()).advance |(&ty, type_param_def)| {
|
||||
check_bounds(cx, type_parameter_id, e.span, ty, type_param_def)
|
||||
check_typaram_bounds(cx, type_parameter_id, e.span, ty, type_param_def)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -279,7 +291,13 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
|
||||
match e.node {
|
||||
expr_cast(source, _) => {
|
||||
check_cast_for_escaping_regions(cx, source, e);
|
||||
check_kind_bounds_of_cast(cx, source, e);
|
||||
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
|
||||
ty::ty_trait(_, _, store, _, bounds) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, source);
|
||||
check_trait_cast_bounds(cx, e.span, source_ty, bounds, store)
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
expr_copy(expr) => {
|
||||
// Note: This is the only place where we must check whether the
|
||||
@ -307,14 +325,14 @@ 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));
|
||||
let type_param_defs =
|
||||
ty::lookup_item_type(cx.tcx, did).generics.type_param_defs;
|
||||
for ts.iter().zip(type_param_defs.iter()).advance |(&ty, type_param_def)| {
|
||||
check_bounds(cx, aty.id, aty.span, ty, type_param_def)
|
||||
check_typaram_bounds(cx, aty.id, aty.span, ty, type_param_def)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -323,20 +341,29 @@ fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) {
|
||||
visit::visit_ty(aty, (cx, v));
|
||||
}
|
||||
|
||||
pub fn check_bounds(cx: Context,
|
||||
_type_parameter_id: node_id,
|
||||
sp: span,
|
||||
ty: ty::t,
|
||||
type_param_def: &ty::TypeParameterDef)
|
||||
// Calls "any_missing" if any bounds were missing.
|
||||
pub fn check_builtin_bounds(cx: Context, ty: ty::t, bounds: ty::BuiltinBounds,
|
||||
any_missing: &fn(ty::BuiltinBounds))
|
||||
{
|
||||
let kind = ty::type_contents(cx.tcx, ty);
|
||||
let mut missing = ty::EmptyBuiltinBounds();
|
||||
for type_param_def.bounds.builtin_bounds.each |bound| {
|
||||
for bounds.each |bound| {
|
||||
if !kind.meets_bound(cx.tcx, bound) {
|
||||
missing.add(bound);
|
||||
}
|
||||
}
|
||||
if !missing.is_empty() {
|
||||
any_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_typaram_bounds(cx: Context,
|
||||
_type_parameter_id: node_id,
|
||||
sp: span,
|
||||
ty: ty::t,
|
||||
type_param_def: &ty::TypeParameterDef)
|
||||
{
|
||||
do check_builtin_bounds(cx, ty, type_param_def.bounds.builtin_bounds) |missing| {
|
||||
cx.tcx.sess.span_err(
|
||||
sp,
|
||||
fmt!("instantiating a type parameter with an incompatible type \
|
||||
@ -346,6 +373,38 @@ pub fn check_bounds(cx: Context,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_freevar_bounds(cx: Context, sp: span, ty: ty::t,
|
||||
bounds: ty::BuiltinBounds)
|
||||
{
|
||||
do check_builtin_bounds(cx, ty, bounds) |missing| {
|
||||
cx.tcx.sess.span_err(
|
||||
sp,
|
||||
fmt!("cannot capture variable of type `%s`, which does not fulfill \
|
||||
`%s`, in a bounded closure",
|
||||
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx)));
|
||||
cx.tcx.sess.span_note(
|
||||
sp,
|
||||
fmt!("this closure's environment must satisfy `%s`",
|
||||
bounds.user_string(cx.tcx)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_trait_cast_bounds(cx: Context, sp: span, ty: ty::t,
|
||||
bounds: ty::BuiltinBounds, store: ty::TraitStore) {
|
||||
do check_builtin_bounds(cx, ty, bounds) |missing| {
|
||||
cx.tcx.sess.span_err(sp,
|
||||
fmt!("cannot pack type `%s`, which does not fulfill \
|
||||
`%s`, as a trait bounded by %s",
|
||||
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx),
|
||||
bounds.user_string(cx.tcx)));
|
||||
}
|
||||
// FIXME(#3569): Remove this check when the corresponding restriction
|
||||
// is made with type contents.
|
||||
if store == ty::UniqTraitStore && !ty::type_is_owned(cx.tcx, ty) {
|
||||
cx.tcx.sess.span_err(sp, "uniquely-owned trait objects must be sendable");
|
||||
}
|
||||
}
|
||||
|
||||
fn is_nullary_variant(cx: Context, ex: @expr) -> bool {
|
||||
match ex.node {
|
||||
expr_path(_) => {
|
||||
@ -528,19 +587,3 @@ pub fn check_cast_for_escaping_regions(
|
||||
cx.tcx.region_maps.is_subregion_of(r_sub, r_sup)
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that values placed into a ~Trait are copyable and sendable.
|
||||
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, _) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, source);
|
||||
if !ty::type_is_owned(cx.tcx, source_ty) {
|
||||
cx.tcx.sess.span_err(
|
||||
target.span,
|
||||
"uniquely-owned trait objects must be sendable");
|
||||
}
|
||||
}
|
||||
_ => {} // Nothing to do.
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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| {
|
||||
|
@ -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) => {
|
||||
|
@ -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)
|
||||
},
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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]));
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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) => {
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
|
@ -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),
|
||||
@ -1850,7 +1856,7 @@ impl TypeContents {
|
||||
}
|
||||
|
||||
pub fn noncopyable(_cx: ctxt) -> TypeContents {
|
||||
TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_OWNED_CLOSURE +
|
||||
TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_NONCOPY_TRAIT +
|
||||
TC_EMPTY_ENUM
|
||||
}
|
||||
|
||||
@ -1899,13 +1905,19 @@ impl TypeContents {
|
||||
}
|
||||
|
||||
pub fn needs_drop(&self, cx: ctxt) -> bool {
|
||||
if self.intersects(TC_NONCOPY_TRAIT) {
|
||||
// Currently all noncopyable existentials are 2nd-class types
|
||||
// behind owned pointers. With dynamically-sized types, remove
|
||||
// this assertion.
|
||||
assert!(self.intersects(TC_OWNED_POINTER));
|
||||
}
|
||||
let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx);
|
||||
self.intersects(tc)
|
||||
}
|
||||
|
||||
pub fn owned(_cx: ctxt) -> TypeContents {
|
||||
//! Any kind of owned contents.
|
||||
TC_OWNED_CLOSURE + TC_OWNED_POINTER + TC_OWNED_VEC
|
||||
TC_OWNED_POINTER + TC_OWNED_VEC
|
||||
}
|
||||
}
|
||||
|
||||
@ -1939,8 +1951,8 @@ static TC_OWNED_POINTER: TypeContents = TypeContents{bits: 0b0000_0000_0010};
|
||||
/// Contains an owned vector ~[] or owned string ~str
|
||||
static TC_OWNED_VEC: TypeContents = TypeContents{bits: 0b0000_0000_0100};
|
||||
|
||||
/// Contains a ~fn() or a ~Trait, which is non-copyable.
|
||||
static TC_OWNED_CLOSURE: TypeContents = TypeContents{bits: 0b0000_0000_1000};
|
||||
/// Contains a non-copyable ~fn() or a ~Trait (NOT a ~fn:Copy() or ~Trait:Copy).
|
||||
static TC_NONCOPY_TRAIT: TypeContents = TypeContents{bits: 0b0000_0000_1000};
|
||||
|
||||
/// Type with a destructor
|
||||
static TC_DTOR: TypeContents = TypeContents{bits: 0b0000_0001_0000};
|
||||
@ -2054,18 +2066,19 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
|
||||
TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache)))
|
||||
}
|
||||
|
||||
ty_trait(_, _, UniqTraitStore, _) => {
|
||||
TC_OWNED_CLOSURE
|
||||
ty_trait(_, _, UniqTraitStore, _, _bounds) => {
|
||||
// FIXME(#3569): Make this conditional on the trait's bounds.
|
||||
TC_NONCOPY_TRAIT + TC_OWNED_POINTER
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -2178,7 +2191,9 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
|
||||
match sigil {
|
||||
ast::BorrowedSigil => TC_BORROWED_POINTER,
|
||||
ast::ManagedSigil => TC_MANAGED,
|
||||
ast::OwnedSigil => TC_OWNED_CLOSURE
|
||||
// FIXME(#3569): Looks like noncopyability should depend
|
||||
// on the bounds, but I don't think this case ever comes up.
|
||||
ast::OwnedSigil => TC_NONCOPY_TRAIT + TC_OWNED_POINTER,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2252,7 +2267,11 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
|
||||
let st = match cty.sigil {
|
||||
ast::BorrowedSigil => TC_BORROWED_POINTER,
|
||||
ast::ManagedSigil => TC_MANAGED,
|
||||
ast::OwnedSigil => TC_OWNED_CLOSURE
|
||||
ast::OwnedSigil => if cty.bounds.contains_elem(BoundCopy) {
|
||||
TC_OWNED_POINTER
|
||||
} else {
|
||||
TC_OWNED_POINTER + TC_NONCOPY_TRAIT
|
||||
}
|
||||
};
|
||||
let rt = borrowed_contents(cty.region, m_imm);
|
||||
let ot = match cty.onceness {
|
||||
@ -2347,7 +2366,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 +2519,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 +2810,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 +3460,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 +3794,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 +4474,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()))
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 ||
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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}
|
||||
}
|
||||
|
@ -365,6 +365,11 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
||||
|
||||
s.push_str("fn");
|
||||
|
||||
if !cty.bounds.is_empty() {
|
||||
s.push_str(":");
|
||||
}
|
||||
s.push_str(cty.bounds.repr(cx));
|
||||
|
||||
push_sig_to_str(cx, &mut s, &cty.sig);
|
||||
|
||||
return s;
|
||||
@ -451,11 +456,14 @@ 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_sep = if bounds.is_empty() { "" } else { ":" };
|
||||
let bound_str = bounds.repr(cx);
|
||||
fmt!("%s%s%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
|
||||
bound_sep, bound_str)
|
||||
}
|
||||
ty_evec(ref mt, vs) => {
|
||||
vstore_ty_to_str(cx, mt, vs)
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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(¶ms)))
|
||||
.add_tys(cx.ty_vars_global(¶ms)), @opt_vec::Empty)
|
||||
}
|
||||
|
||||
fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item {
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -58,5 +58,5 @@ fn cat(in_x : uint, in_y : int, in_name: ~str) -> cat {
|
||||
|
||||
fn main() {
|
||||
let nyan : @noisy = @cat(0, 2, ~"nyan") as @noisy;
|
||||
nyan.eat(); //~ ERROR type `@noisy` does not implement any method in scope named `eat`
|
||||
nyan.eat(); //~ ERROR does not implement any method in scope named `eat`
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
struct X {
|
||||
field: @fn:Copy(),
|
||||
}
|
||||
|
||||
fn foo(blk: @fn()) -> X {
|
||||
return X { field: blk }; //~ ERROR expected bounds `Copy` but found no bounds
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
use std::comm;
|
||||
|
||||
// If this were legal you could use it to copy captured noncopyables.
|
||||
// Issue (#2828)
|
||||
|
||||
fn foo(blk: ~fn:Copy()) {
|
||||
blk();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (p,c) = comm::stream();
|
||||
do foo {
|
||||
c.send(()); //~ ERROR does not fulfill `Copy`
|
||||
}
|
||||
p.recv();
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
fn bar(blk: &fn:'static()) {
|
||||
}
|
||||
|
||||
fn foo(x: &()) {
|
||||
do bar {
|
||||
let _ = x; //~ ERROR does not fulfill `'static`
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
|
||||
fn take_any(_: &fn()) {
|
||||
}
|
||||
|
||||
@ -7,6 +8,9 @@ fn take_copyable(_: &fn:Copy()) {
|
||||
fn take_copyable_owned(_: &fn:Copy+Owned()) {
|
||||
}
|
||||
|
||||
fn take_const_owned(_: &fn:Const+Owned()) {
|
||||
}
|
||||
|
||||
fn give_any(f: &fn()) {
|
||||
take_any(f);
|
||||
take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds
|
||||
@ -29,6 +33,7 @@ fn give_copyable_owned(f: &fn:Copy+Owned()) {
|
||||
take_any(f);
|
||||
take_copyable(f);
|
||||
take_copyable_owned(f);
|
||||
take_const_owned(f); //~ ERROR expected bounds `Owned+Const` but found bounds `Copy+Owned`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -13,5 +13,5 @@ extern fn f() {
|
||||
|
||||
fn main() {
|
||||
// extern functions are *u8 types
|
||||
let _x: &fn() = f; //~ ERROR mismatched types: expected `&fn()` but found `*u8`
|
||||
let _x: &fn() = f; //~ ERROR found `*u8`
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
fn foopy() {}
|
||||
|
||||
static f: &'static fn() = foopy; //~ ERROR mismatched types: expected `&'static fn()`
|
||||
static f: &'static fn() = foopy; //~ ERROR found extern fn
|
||||
|
||||
fn main () {
|
||||
f();
|
||||
|
@ -16,8 +16,8 @@ pub enum TraitWrapper {
|
||||
|
||||
fn get_tw_map<'lt>(tw: &'lt TraitWrapper) -> &'lt MyTrait {
|
||||
match *tw {
|
||||
A(~ref map) => map, //~ ERROR mismatched types: expected `~MyTrait` but found a ~-box pattern
|
||||
A(~ref map) => map, //~ ERROR found a ~-box pattern
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
pub fn main() {}
|
||||
|
@ -17,5 +17,5 @@ fn main() {
|
||||
let x: @Map<~str, ~str> = @HashMap::new::<~str, ~str>() as
|
||||
@Map<~str, ~str>;
|
||||
let y: @Map<uint, ~str> = @x;
|
||||
//~^ ERROR mismatched types: expected `@std::container::Map<uint,~str>`
|
||||
//~^ ERROR expected trait std::container::Map but found @-ptr
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
fn foo(f: &fn()) { f() }
|
||||
|
||||
fn main() {
|
||||
~"" || 42; //~ ERROR binary operation || cannot be applied to type `~str`
|
||||
foo || {}; //~ ERROR binary operation || cannot be applied to type `extern "Rust" fn(&fn())`
|
||||
~"" || 42; //~ ERROR binary operation || cannot be applied to type
|
||||
foo || {}; //~ ERROR binary operation || cannot be applied to type
|
||||
//~^ NOTE did you forget the `do` keyword for the call?
|
||||
}
|
||||
|
28
src/test/compile-fail/trait-bounds-cant-coerce.rs
Normal file
28
src/test/compile-fail/trait-bounds-cant-coerce.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
trait Foo {
|
||||
}
|
||||
|
||||
fn a(_x: ~Foo:Owned) {
|
||||
}
|
||||
|
||||
fn b(_x: ~Foo:Owned+Copy) {
|
||||
}
|
||||
|
||||
fn c(x: ~Foo:Const+Owned) {
|
||||
b(x); //~ ERROR expected bounds `Copy+Owned`
|
||||
}
|
||||
|
||||
fn d(x: ~Foo) {
|
||||
a(x); //~ ERROR found no bounds
|
||||
}
|
||||
|
||||
fn main() { }
|
19
src/test/compile-fail/trait-bounds-not-on-bare-trait.rs
Normal file
19
src/test/compile-fail/trait-bounds-not-on-bare-trait.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
trait Foo {
|
||||
}
|
||||
|
||||
// This should emit the less confusing error, not the more confusing one.
|
||||
|
||||
fn foo(_x: Foo:Owned) { //~ERROR reference to trait `Foo` where a type is expected
|
||||
}
|
||||
|
||||
fn main() { }
|
19
src/test/compile-fail/trait-bounds-not-on-impl.rs
Normal file
19
src/test/compile-fail/trait-bounds-not-on-impl.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
trait Foo {
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo:Owned for Bar { //~ ERROR bounded traits are only valid in type position
|
||||
}
|
||||
|
||||
fn main() { }
|
15
src/test/compile-fail/trait-bounds-not-on-struct.rs
Normal file
15
src/test/compile-fail/trait-bounds-not-on-struct.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
struct Foo;
|
||||
|
||||
fn foo(_x: ~Foo:Owned) { } //~ ERROR kind bounds can only be used on trait types
|
||||
|
||||
fn main() { }
|
23
src/test/run-pass/closure-bounds-can-capture-chan.rs
Normal file
23
src/test/run-pass/closure-bounds-can-capture-chan.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
use std::comm;
|
||||
|
||||
fn foo(blk: ~fn:Owned()) {
|
||||
blk();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (p,c) = comm::stream();
|
||||
do foo {
|
||||
c.send(());
|
||||
}
|
||||
p.recv();
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// xfail-pretty
|
||||
|
||||
// Tests correct copying of heap closures' environments.
|
||||
|
||||
fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) {
|
||||
(copy x, x)
|
||||
}
|
||||
fn main() {
|
||||
let v = ~[~[1,2,3],~[4,5,6]]; // shouldn't get double-freed
|
||||
let (f1,f2) = do foo {
|
||||
assert!(v.len() == 2);
|
||||
};
|
||||
f1();
|
||||
f2();
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// xfail-pretty
|
||||
|
||||
// Tests correct copying of heap closures' environments.
|
||||
|
||||
fn bar<T: Copy>(x: T) -> (T, T) {
|
||||
(copy x, x)
|
||||
}
|
||||
fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) {
|
||||
bar(x)
|
||||
}
|
||||
fn main() {
|
||||
let v = ~[~[1,2,3],~[4,5,6]]; // shouldn't get double-freed
|
||||
let (f1,f2) = do foo {
|
||||
assert!(v.len() == 2);
|
||||
};
|
||||
f1();
|
||||
f2();
|
||||
}
|
28
src/test/run-pass/trait-bounds-basic.rs
Normal file
28
src/test/run-pass/trait-bounds-basic.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
trait Foo {
|
||||
}
|
||||
|
||||
fn a(_x: ~Foo) {
|
||||
}
|
||||
|
||||
fn b(_x: ~Foo:Owned) {
|
||||
}
|
||||
|
||||
fn c(x: ~Foo:Const+Owned) {
|
||||
a(x);
|
||||
}
|
||||
|
||||
fn d(x: ~Foo:Owned+Copy) {
|
||||
b(x);
|
||||
}
|
||||
|
||||
fn main() { }
|
Loading…
x
Reference in New Issue
Block a user