Skip to content

Commit 7b96878

Browse files
committed
Infer default static/Owned bounds for unbounded heap fns/traits (rust-lang#7264)
1 parent 12e09af commit 7b96878

25 files changed

+177
-87
lines changed

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

+1-1
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 =

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -4497,7 +4497,9 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
44974497
};
44984498
let trait_lang_item = tcx.lang_items.ty_visitor();
44994499
let trait_ref = @TraitRef { def_id: trait_lang_item, substs: substs };
4500+
let mut static_trait_bound = EmptyBuiltinBounds();
4501+
static_trait_bound.add(BoundStatic);
45004502
(trait_ref,
45014503
mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs,
4502-
BoxTraitStore, ast::m_imm, EmptyBuiltinBounds()))
4504+
BoxTraitStore, ast::m_imm, static_trait_bound))
45034505
}

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/libsyntax/ast.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,11 @@ pub struct TyClosure {
771771
purity: purity,
772772
onceness: Onceness,
773773
decl: fn_decl,
774-
bounds: OptVec<TyParamBound>
774+
// Optional optvec distinguishes between "fn()" and "fn:()" so we can
775+
// implement issue #7264. None means "fn()", which means infer a default
776+
// bound based on pointer sigil during typeck. Some(Empty) means "fn:()",
777+
// which means use no bounds (e.g., not even Owned on a ~fn()).
778+
bounds: Option<OptVec<TyParamBound>>,
775779
}
776780

777781
#[deriving(Eq, Encodable, Decodable)]
@@ -795,7 +799,7 @@ pub enum ty_ {
795799
ty_closure(@TyClosure),
796800
ty_bare_fn(@TyBareFn),
797801
ty_tup(~[@Ty]),
798-
ty_path(@Path, @OptVec<TyParamBound>, node_id),
802+
ty_path(@Path, @Option<OptVec<TyParamBound>>, node_id), // for #7264; see above
799803
ty_mac(mac),
800804
// ty_infer means the type should be inferred instead of it having been
801805
// specified. This should only appear at the "top level" of a type and not

src/libsyntax/ext/build.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub trait AstBuilder {
4646
fn ty_mt(&self, ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt;
4747

4848
fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty;
49-
fn ty_path(&self, @ast::Path, @OptVec<ast::TyParamBound>) -> @ast::Ty;
49+
fn ty_path(&self, @ast::Path, @Option<OptVec<ast::TyParamBound>>) -> @ast::Ty;
5050
fn ty_ident(&self, span: span, idents: ast::ident) -> @ast::Ty;
5151

5252
fn ty_rptr(&self, span: span,
@@ -265,7 +265,7 @@ impl AstBuilder for @ExtCtxt {
265265
}
266266
}
267267

268-
fn ty_path(&self, path: @ast::Path, bounds: @OptVec<ast::TyParamBound>)
268+
fn ty_path(&self, path: @ast::Path, bounds: @Option<OptVec<ast::TyParamBound>>)
269269
-> @ast::Ty {
270270
self.ty(path.span,
271271
ast::ty_path(path, bounds, self.next_id()))
@@ -275,7 +275,7 @@ impl AstBuilder for @ExtCtxt {
275275
// to generate a bounded existential trait type.
276276
fn ty_ident(&self, span: span, ident: ast::ident)
277277
-> @ast::Ty {
278-
self.ty_path(self.path_ident(span, ident), @opt_vec::Empty)
278+
self.ty_path(self.path_ident(span, ident), @None)
279279
}
280280

281281
fn ty_rptr(&self,
@@ -306,7 +306,7 @@ impl AstBuilder for @ExtCtxt {
306306
],
307307
None,
308308
~[ ty ]),
309-
@opt_vec::Empty)
309+
@None)
310310
}
311311

312312
fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field {
@@ -344,7 +344,7 @@ impl AstBuilder for @ExtCtxt {
344344
fn ty_vars_global(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] {
345345
opt_vec::take_vec(
346346
ty_params.map(|p| self.ty_path(
347-
self.path_global(dummy_sp(), ~[p.ident]), @opt_vec::Empty)))
347+
self.path_global(dummy_sp(), ~[p.ident]), @None)))
348348
}
349349

350350
fn strip_bounds(&self, generics: &Generics) -> Generics {

src/libsyntax/ext/deriving/generic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ impl<'self> TraitDef<'self> {
357357
// Create the type of `self`.
358358
let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime,
359359
opt_vec::take_vec(self_ty_params)),
360-
@opt_vec::Empty);
360+
@None);
361361

362362
let doc_attr = cx.attribute(
363363
span,

src/libsyntax/ext/deriving/ty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl<'self> Path<'self> {
6363
self_generics: &Generics)
6464
-> @ast::Ty {
6565
cx.ty_path(self.to_path(cx, span,
66-
self_ty, self_generics), @opt_vec::Empty)
66+
self_ty, self_generics), @None)
6767
}
6868
pub fn to_path(&self,
6969
cx: @ExtCtxt,
@@ -143,7 +143,7 @@ impl<'self> Ty<'self> {
143143
Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
144144
Self => {
145145
cx.ty_path(self.to_path(cx, span, self_ty, self_generics),
146-
@opt_vec::Empty)
146+
@None)
147147
}
148148
Tuple(ref fields) => {
149149
let ty = if fields.is_empty() {

src/libsyntax/ext/pipes/pipec.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl gen_send for message {
5959

6060
let pipe_ty = cx.ty_path(
6161
path(~[this.data_name()], span)
62-
.add_tys(cx.ty_vars(&this.generics.ty_params)), @opt_vec::Empty);
62+
.add_tys(cx.ty_vars(&this.generics.ty_params)), @None);
6363
let args_ast = vec::append(
6464
~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)],
6565
args_ast);
@@ -115,7 +115,7 @@ impl gen_send for message {
115115

116116
let mut rty = cx.ty_path(path(~[next.data_name()],
117117
span)
118-
.add_tys(copy next_state.tys), @opt_vec::Empty);
118+
.add_tys(copy next_state.tys), @None);
119119
if try {
120120
rty = cx.ty_option(rty);
121121
}
@@ -144,7 +144,7 @@ impl gen_send for message {
144144
cx.ty_path(
145145
path(~[this.data_name()], span)
146146
.add_tys(cx.ty_vars(
147-
&this.generics.ty_params)), @opt_vec::Empty))],
147+
&this.generics.ty_params)), @None))],
148148
args_ast);
149149

150150
let message_args = if arg_names.len() == 0 {
@@ -190,7 +190,7 @@ impl gen_send for message {
190190

191191
fn to_ty(&mut self, cx: @ExtCtxt) -> @ast::Ty {
192192
cx.ty_path(path(~[cx.ident_of(self.name())], self.span())
193-
.add_tys(cx.ty_vars(&self.get_generics().ty_params)), @opt_vec::Empty)
193+
.add_tys(cx.ty_vars(&self.get_generics().ty_params)), @None)
194194
}
195195
}
196196

@@ -224,7 +224,7 @@ impl to_type_decls for state {
224224
cx.ty_path(
225225
path(~[cx.ident_of(dir),
226226
cx.ident_of(next_name)], span)
227-
.add_tys(copy next_state.tys), @opt_vec::Empty))
227+
.add_tys(copy next_state.tys), @None))
228228
}
229229
None => tys
230230
};
@@ -277,8 +277,8 @@ impl to_type_decls for state {
277277
self.data_name()],
278278
dummy_sp())
279279
.add_tys(cx.ty_vars(
280-
&self.generics.ty_params)), @opt_vec::Empty)),
281-
@opt_vec::Empty),
280+
&self.generics.ty_params)), @None)),
281+
@None),
282282
cx.strip_bounds(&self.generics)));
283283
}
284284
else {
@@ -297,8 +297,8 @@ impl to_type_decls for state {
297297
self.data_name()],
298298
dummy_sp())
299299
.add_tys(cx.ty_vars_global(
300-
&self.generics.ty_params)), @opt_vec::Empty),
301-
self.proto.buffer_ty_path(cx)]), @opt_vec::Empty),
300+
&self.generics.ty_params)), @None),
301+
self.proto.buffer_ty_path(cx)]), @None),
302302
cx.strip_bounds(&self.generics)));
303303
};
304304
items
@@ -383,7 +383,7 @@ impl gen_init for protocol {
383383
cx.ty_path(path(~[cx.ident_of("super"),
384384
cx.ident_of("__Buffer")],
385385
copy self.span)
386-
.add_tys(cx.ty_vars_global(&params)), @opt_vec::Empty)
386+
.add_tys(cx.ty_vars_global(&params)), @None)
387387
}
388388

389389
fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item {

src/libsyntax/ext/pipes/proto.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use codemap::span;
1313
use ext::base::ExtCtxt;
1414
use ext::build::AstBuilder;
1515
use ext::pipes::ast_builder::{append_types, path};
16-
use opt_vec;
1716

1817
#[deriving(Eq)]
1918
pub enum direction { send, recv }
@@ -100,7 +99,7 @@ impl state_ {
10099
pub fn to_ty(&self, cx: @ExtCtxt) -> @ast::Ty {
101100
cx.ty_path
102101
(path(~[cx.ident_of(self.name)],self.span).add_tys(
103-
cx.ty_vars(&self.generics.ty_params)), @opt_vec::Empty)
102+
cx.ty_vars(&self.generics.ty_params)), @None)
104103
}
105104

106105
/// Iterate over the states that can be reached in one message

src/libsyntax/fold.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,12 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
651651
span: fld.new_span(f.span),
652652
}
653653
}
654+
fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold)
655+
-> Option<OptVec<TyParamBound>> {
656+
do b.map |bounds| {
657+
do bounds.map |bound| { fold_ty_param_bound(bound, fld) }
658+
}
659+
}
654660
match *t {
655661
ty_nil | ty_bot | ty_infer => copy *t,
656662
ty_box(ref mt) => ty_box(fold_mt(mt, fld)),
@@ -664,7 +670,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
664670
purity: f.purity,
665671
region: f.region,
666672
onceness: f.onceness,
667-
bounds: f.bounds.map(|x| fold_ty_param_bound(x, fld)),
673+
bounds: fold_opt_bounds(&f.bounds, fld),
668674
decl: fold_fn_decl(&f.decl, fld),
669675
lifetimes: copy f.lifetimes,
670676
})
@@ -679,8 +685,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
679685
}
680686
ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(*ty))),
681687
ty_path(path, bounds, id) =>
682-
ty_path(fld.fold_path(path),
683-
@bounds.map(|x| fold_ty_param_bound(x, fld)), fld.new_id(id)),
688+
ty_path(fld.fold_path(path), @fold_opt_bounds(bounds, fld), fld.new_id(id)),
684689
ty_fixed_length_vec(ref mt, e) => {
685690
ty_fixed_length_vec(
686691
fold_mt(mt, fld),

0 commit comments

Comments
 (0)