Skip to content

Commit 36d7f60

Browse files
committed
auto merge of #7354 : bblum/rust/trait-bounds, r=pcwalton
r? @nikomatsakis
2 parents 32adc0e + c37ccac commit 36d7f60

33 files changed

+362
-145
lines changed

src/libextra/io_util.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use core::io::{Reader, BytesReader};
1212
use core::io;
13+
use core::cast;
1314

1415
/// An implementation of the io::Reader interface which reads a buffer of bytes
1516
pub struct BufReader {
@@ -29,10 +30,13 @@ impl BufReader {
2930
}
3031

3132
fn as_bytes_reader<A>(&self, f: &fn(&BytesReader) -> A) -> A {
33+
// XXX FIXME(#5723)
34+
let bytes = ::core::util::id::<&[u8]>(self.buf);
35+
let bytes: &'static [u8] = unsafe { cast::transmute(bytes) };
3236
// Recreating the BytesReader state every call since
3337
// I can't get the borrowing to work correctly
3438
let bytes_reader = BytesReader {
35-
bytes: ::core::util::id::<&[u8]>(self.buf),
39+
bytes: bytes,
3640
pos: @mut *self.pos
3741
};
3842

src/libextra/test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ type MonitorMsg = (TestDesc, TestResult);
423423
424424
fn run_tests(opts: &TestOpts,
425425
tests: ~[TestDescAndFn],
426-
callback: @fn(e: TestEvent)) {
426+
callback: &fn(e: TestEvent)) {
427427
428428
let filtered_tests = filter_tests(opts, tests);
429429
let filtered_descs = filtered_tests.map(|t| copy t.desc);

src/librustc/metadata/encoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
959959
encode_attributes(ebml_w, item.attrs);
960960
match ty.node {
961961
ast::ty_path(path, bounds, _) if path.idents.len() == 1 => {
962-
assert!(bounds.is_empty());
962+
assert!(bounds.is_none());
963963
encode_impl_type_basename(ecx, ebml_w,
964964
ast_util::path_to_ident(path));
965965
}

src/librustc/middle/kind.rs

+4-17
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
128128
// Yes, it's a destructor.
129129
match self_type.node {
130130
ty_path(_, bounds, path_node_id) => {
131-
assert!(bounds.is_empty());
131+
assert!(bounds.is_none());
132132
let struct_def = cx.tcx.def_map.get_copy(
133133
&path_node_id);
134134
let struct_did =
@@ -169,10 +169,6 @@ fn with_appropriate_checker(cx: Context, id: node_id,
169169
let id = ast_util::def_id_of_def(fv.def).node;
170170
let var_t = ty::node_id_to_type(cx.tcx, id);
171171

172-
// FIXME(#3569): Once closure capabilities are restricted based on their
173-
// incoming bounds, make this check conditional based on the bounds.
174-
if !check_owned(cx, var_t, fv.span) { return; }
175-
176172
// check that only immutable variables are implicitly copied in
177173
check_imm_free_var(cx, fv.def, fv.span);
178174

@@ -184,10 +180,6 @@ fn with_appropriate_checker(cx: Context, id: node_id,
184180
let id = ast_util::def_id_of_def(fv.def).node;
185181
let var_t = ty::node_id_to_type(cx.tcx, id);
186182

187-
// FIXME(#3569): Once closure capabilities are restricted based on their
188-
// incoming bounds, make this check conditional based on the bounds.
189-
if !check_durable(cx.tcx, var_t, fv.span) { return; }
190-
191183
// check that only immutable variables are implicitly copied in
192184
check_imm_free_var(cx, fv.def, fv.span);
193185

@@ -293,9 +285,9 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
293285
expr_cast(source, _) => {
294286
check_cast_for_escaping_regions(cx, source, e);
295287
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
296-
ty::ty_trait(_, _, store, _, bounds) => {
288+
ty::ty_trait(_, _, _, _, bounds) => {
297289
let source_ty = ty::expr_ty(cx.tcx, source);
298-
check_trait_cast_bounds(cx, e.span, source_ty, bounds, store)
290+
check_trait_cast_bounds(cx, e.span, source_ty, bounds)
299291
}
300292
_ => { }
301293
}
@@ -391,19 +383,14 @@ pub fn check_freevar_bounds(cx: Context, sp: span, ty: ty::t,
391383
}
392384

393385
pub fn check_trait_cast_bounds(cx: Context, sp: span, ty: ty::t,
394-
bounds: ty::BuiltinBounds, store: ty::TraitStore) {
386+
bounds: ty::BuiltinBounds) {
395387
do check_builtin_bounds(cx, ty, bounds) |missing| {
396388
cx.tcx.sess.span_err(sp,
397389
fmt!("cannot pack type `%s`, which does not fulfill \
398390
`%s`, as a trait bounded by %s",
399391
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx),
400392
bounds.user_string(cx.tcx)));
401393
}
402-
// FIXME(#3569): Remove this check when the corresponding restriction
403-
// is made with type contents.
404-
if store == ty::UniqTraitStore && !ty::type_is_owned(cx.tcx, ty) {
405-
cx.tcx.sess.span_err(sp, "uniquely-owned trait objects must be sendable");
406-
}
407394
}
408395

409396
fn is_nullary_variant(cx: Context, ex: @expr) -> bool {

src/librustc/middle/resolve.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -4195,15 +4195,19 @@ impl Resolver {
41954195
}
41964196
}
41974197

4198-
for bounds.iter().advance |bound| {
4199-
self.resolve_type_parameter_bound(bound, visitor);
4200-
}
4198+
do bounds.map |bound_vec| {
4199+
for bound_vec.iter().advance |bound| {
4200+
self.resolve_type_parameter_bound(bound, visitor);
4201+
}
4202+
};
42014203
}
42024204

42034205
ty_closure(c) => {
4204-
for c.bounds.iter().advance |bound| {
4205-
self.resolve_type_parameter_bound(bound, visitor);
4206-
}
4206+
do c.bounds.map |bounds| {
4207+
for bounds.iter().advance |bound| {
4208+
self.resolve_type_parameter_bound(bound, visitor);
4209+
}
4210+
};
42074211
visit_ty(ty, ((), visitor));
42084212
}
42094213

src/librustc/middle/ty.rs

+48-22
Original file line numberDiff line numberDiff line change
@@ -2063,20 +2063,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
20632063
TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache)))
20642064
}
20652065

2066-
ty_trait(_, _, UniqTraitStore, _, _bounds) => {
2067-
// FIXME(#3569): Make this conditional on the trait's bounds.
2068-
TC_NONCOPY_TRAIT + TC_OWNED_POINTER
2069-
}
2070-
2071-
ty_trait(_, _, BoxTraitStore, mutbl, _bounds) => {
2072-
match mutbl {
2073-
ast::m_mutbl => TC_MANAGED + TC_MUTABLE,
2074-
_ => TC_MANAGED
2075-
}
2076-
}
2077-
2078-
ty_trait(_, _, RegionTraitStore(r), mutbl, _bounds) => {
2079-
borrowed_contents(r, mutbl)
2066+
ty_trait(_, _, store, mutbl, bounds) => {
2067+
trait_contents(store, mutbl, bounds)
20802068
}
20812069

20822070
ty_rptr(r, mt) => {
@@ -2261,23 +2249,59 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
22612249
}
22622250

22632251
fn closure_contents(cty: &ClosureTy) -> TypeContents {
2252+
// Closure contents are just like trait contents, but with potentially
2253+
// even more stuff.
22642254
let st = match cty.sigil {
2265-
ast::BorrowedSigil => TC_BORROWED_POINTER,
2266-
ast::ManagedSigil => TC_MANAGED,
2267-
ast::OwnedSigil => if cty.bounds.contains_elem(BoundCopy) {
2268-
TC_OWNED_POINTER
2269-
} else {
2270-
TC_OWNED_POINTER + TC_NONCOPY_TRAIT
2271-
}
2255+
ast::BorrowedSigil =>
2256+
trait_contents(RegionTraitStore(cty.region), m_imm, cty.bounds)
2257+
+ TC_BORROWED_POINTER, // might be an env packet even if static
2258+
ast::ManagedSigil =>
2259+
trait_contents(BoxTraitStore, m_imm, cty.bounds),
2260+
ast::OwnedSigil =>
2261+
trait_contents(UniqTraitStore, m_imm, cty.bounds),
22722262
};
2263+
// FIXME(#3569): This borrowed_contents call should be taken care of in
2264+
// trait_contents, after ~Traits and @Traits can have region bounds too.
2265+
// This one here is redundant for &fns but important for ~fns and @fns.
22732266
let rt = borrowed_contents(cty.region, m_imm);
2267+
// This also prohibits "@once fn" from being copied, which allows it to
2268+
// be called. Neither way really makes much sense.
22742269
let ot = match cty.onceness {
22752270
ast::Once => TC_ONCE_CLOSURE,
22762271
ast::Many => TC_NONE
22772272
};
22782273
st + rt + ot
22792274
}
22802275

2276+
fn trait_contents(store: TraitStore, mutbl: ast::mutability,
2277+
bounds: BuiltinBounds) -> TypeContents {
2278+
let st = match store {
2279+
UniqTraitStore => TC_OWNED_POINTER,
2280+
BoxTraitStore => TC_MANAGED,
2281+
RegionTraitStore(r) => borrowed_contents(r, mutbl),
2282+
};
2283+
let mt = match mutbl { ast::m_mutbl => TC_MUTABLE, _ => TC_NONE };
2284+
// We get additional "special type contents" for each bound that *isn't*
2285+
// on the trait. So iterate over the inverse of the bounds that are set.
2286+
// This is like with typarams below, but less "pessimistic" and also
2287+
// dependent on the trait store.
2288+
let mut bt = TC_NONE;
2289+
for (AllBuiltinBounds() - bounds).each |bound| {
2290+
bt = bt + match bound {
2291+
BoundCopy if store == UniqTraitStore
2292+
=> TC_NONCOPY_TRAIT,
2293+
BoundCopy => TC_NONE, // @Trait/&Trait are copyable either way
2294+
BoundStatic if bounds.contains_elem(BoundOwned)
2295+
=> TC_NONE, // Owned bound implies static bound.
2296+
BoundStatic => TC_BORROWED_POINTER, // Useful for "@Trait:'static"
2297+
BoundOwned => TC_NON_OWNED,
2298+
BoundConst => TC_MUTABLE,
2299+
BoundSized => TC_NONE, // don't care if interior is sized
2300+
};
2301+
}
2302+
st + mt + bt
2303+
}
2304+
22812305
fn type_param_def_to_contents(cx: ctxt,
22822306
type_param_def: &TypeParameterDef) -> TypeContents
22832307
{
@@ -4497,7 +4521,9 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
44974521
};
44984522
let trait_lang_item = tcx.lang_items.ty_visitor();
44994523
let trait_ref = @TraitRef { def_id: trait_lang_item, substs: substs };
4524+
let mut static_trait_bound = EmptyBuiltinBounds();
4525+
static_trait_bound.add(BoundStatic);
45004526
(trait_ref,
45014527
mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs,
4502-
BoxTraitStore, ast::m_imm, EmptyBuiltinBounds()))
4528+
BoxTraitStore, ast::m_imm, static_trait_bound))
45034529
}

src/librustc/middle/typeck/astconv.rs

+50-25
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
303303
ty::BoxTraitStore
304304
}
305305
};
306-
let bounds = conv_builtin_bounds(this.tcx(), bounds);
306+
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
307307
return ty::mk_trait(tcx,
308308
result.def_id,
309309
copy result.substs,
@@ -386,7 +386,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
386386
bf.abis, &bf.lifetimes, &bf.decl))
387387
}
388388
ast::ty_closure(ref f) => {
389-
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds);
389+
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
390+
// Use corresponding trait store to figure out default bounds
391+
// if none were specified.
392+
ast::BorrowedSigil => ty::RegionTraitStore(ty::re_empty), // dummy region
393+
ast::OwnedSigil => ty::UniqTraitStore,
394+
ast::ManagedSigil => ty::BoxTraitStore,
395+
});
390396
let fn_decl = ty_of_closure(this,
391397
rscope,
392398
f.sigil,
@@ -411,7 +417,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
411417
match a_def {
412418
// But don't emit the error if the user meant to do a trait anyway.
413419
ast::def_trait(*) => { },
414-
_ if !bounds.is_empty() =>
420+
_ if bounds.is_some() =>
415421
tcx.sess.span_err(ast_ty.span,
416422
"kind bounds can only be used on trait types"),
417423
_ => { },
@@ -741,41 +747,60 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
741747
}
742748
}
743749

744-
fn conv_builtin_bounds(tcx: ty::ctxt,
745-
ast_bounds: &OptVec<ast::TyParamBound>)
750+
fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBound>>,
751+
store: ty::TraitStore)
746752
-> ty::BuiltinBounds {
747753
//! Converts a list of bounds from the AST into a `BuiltinBounds`
748754
//! struct. Reports an error if any of the bounds that appear
749755
//! in the AST refer to general traits and not the built-in traits
750756
//! like `Copy` or `Owned`. Used to translate the bounds that
751757
//! appear in closure and trait types, where only builtin bounds are
752758
//! legal.
753-
754-
let mut builtin_bounds = ty::EmptyBuiltinBounds();
755-
for ast_bounds.iter().advance |ast_bound| {
756-
match *ast_bound {
757-
ast::TraitTyParamBound(b) => {
758-
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
759-
ast::def_trait(trait_did) => {
760-
if try_add_builtin_trait(tcx,
761-
trait_did,
762-
&mut builtin_bounds) {
763-
loop; // success
759+
//! If no bounds were specified, we choose a "default" bound based on
760+
//! the allocation type of the fn/trait, as per issue #7264. The user can
761+
//! override this with an empty bounds list, e.g. "~fn:()" or "~Trait:".
762+
763+
match (ast_bounds, store) {
764+
(&Some(ref bound_vec), _) => {
765+
let mut builtin_bounds = ty::EmptyBuiltinBounds();
766+
for bound_vec.iter().advance |ast_bound| {
767+
match *ast_bound {
768+
ast::TraitTyParamBound(b) => {
769+
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
770+
ast::def_trait(trait_did) => {
771+
if try_add_builtin_trait(tcx,
772+
trait_did,
773+
&mut builtin_bounds) {
774+
loop; // success
775+
}
776+
}
777+
_ => { }
764778
}
779+
tcx.sess.span_fatal(
780+
b.path.span,
781+
fmt!("only the builtin traits can be used \
782+
as closure or object bounds"));
783+
}
784+
ast::RegionTyParamBound => {
785+
builtin_bounds.add(ty::BoundStatic);
765786
}
766-
_ => { }
767787
}
768-
tcx.sess.span_fatal(
769-
b.path.span,
770-
fmt!("only the builtin traits can be used \
771-
as closure or object bounds"));
772-
}
773-
ast::RegionTyParamBound => {
774-
builtin_bounds.add(ty::BoundStatic);
775788
}
789+
builtin_bounds
790+
},
791+
// ~Trait is sugar for ~Trait:Owned.
792+
(&None, ty::UniqTraitStore) => {
793+
let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundOwned); set
794+
}
795+
// @Trait is sugar for @Trait:'static.
796+
// &'static Trait is sugar for &'static Trait:'static.
797+
(&None, ty::BoxTraitStore) |
798+
(&None, ty::RegionTraitStore(ty::re_static)) => {
799+
let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundStatic); set
776800
}
801+
// &'r Trait is sugar for &'r Trait:<no-bounds>.
802+
(&None, ty::RegionTraitStore(*)) => ty::EmptyBuiltinBounds(),
777803
}
778-
builtin_bounds
779804
}
780805

781806
pub fn try_add_builtin_trait(tcx: ty::ctxt,

src/libstd/io.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1042,12 +1042,14 @@ pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
10421042
10431043
10441044
// Byte readers
1045-
pub struct BytesReader<'self> {
1046-
bytes: &'self [u8],
1045+
pub struct BytesReader {
1046+
// FIXME(#5723) see other FIXME below
1047+
// FIXME(#7268) this should also be parameterized over <'self>
1048+
bytes: &'static [u8],
10471049
pos: @mut uint
10481050
}
10491051
1050-
impl<'self> Reader for BytesReader<'self> {
1052+
impl Reader for BytesReader {
10511053
fn read(&self, bytes: &mut [u8], len: uint) -> uint {
10521054
let count = uint::min(len, self.bytes.len() - *self.pos);
10531055
@@ -1084,13 +1086,18 @@ impl<'self> Reader for BytesReader<'self> {
10841086
}
10851087
10861088
pub fn with_bytes_reader<T>(bytes: &[u8], f: &fn(@Reader) -> T) -> T {
1089+
// XXX XXX XXX this is glaringly unsound
1090+
// FIXME(#5723) Use a &Reader for the callback's argument. Should be:
1091+
// fn with_bytes_reader<'r, T>(bytes: &'r [u8], f: &fn(&'r Reader) -> T) -> T
1092+
let bytes: &'static [u8] = unsafe { cast::transmute(bytes) };
10871093
f(@BytesReader {
10881094
bytes: bytes,
10891095
pos: @mut 0
10901096
} as @Reader)
10911097
}
10921098
10931099
pub fn with_str_reader<T>(s: &str, f: &fn(@Reader) -> T) -> T {
1100+
// FIXME(#5723): As above.
10941101
with_bytes_reader(s.as_bytes(), f)
10951102
}
10961103

0 commit comments

Comments
 (0)