Skip to content

Commit

Permalink
Infer default static/Owned bounds for unbounded heap fns/traits (rust…
Browse files Browse the repository at this point in the history
  • Loading branch information
bblum committed Jun 26, 2013
1 parent 12e09af commit 7b96878
Show file tree
Hide file tree
Showing 25 changed files with 177 additions and 87 deletions.
2 changes: 1 addition & 1 deletion src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_attributes(ebml_w, item.attrs);
match ty.node {
ast::ty_path(path, bounds, _) if path.idents.len() == 1 => {
assert!(bounds.is_empty());
assert!(bounds.is_none());
encode_impl_type_basename(ecx, ebml_w,
ast_util::path_to_ident(path));
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
// Yes, it's a destructor.
match self_type.node {
ty_path(_, bounds, path_node_id) => {
assert!(bounds.is_empty());
assert!(bounds.is_none());
let struct_def = cx.tcx.def_map.get_copy(
&path_node_id);
let struct_did =
Expand Down
16 changes: 10 additions & 6 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4195,15 +4195,19 @@ impl Resolver {
}
}

for bounds.iter().advance |bound| {
self.resolve_type_parameter_bound(bound, visitor);
}
do bounds.map |bound_vec| {
for bound_vec.iter().advance |bound| {
self.resolve_type_parameter_bound(bound, visitor);
}
};
}

ty_closure(c) => {
for c.bounds.iter().advance |bound| {
self.resolve_type_parameter_bound(bound, visitor);
}
do c.bounds.map |bounds| {
for bounds.iter().advance |bound| {
self.resolve_type_parameter_bound(bound, visitor);
}
};
visit_ty(ty, ((), visitor));
}

Expand Down
4 changes: 3 additions & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4497,7 +4497,9 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
};
let trait_lang_item = tcx.lang_items.ty_visitor();
let trait_ref = @TraitRef { def_id: trait_lang_item, substs: substs };
let mut static_trait_bound = EmptyBuiltinBounds();
static_trait_bound.add(BoundStatic);
(trait_ref,
mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs,
BoxTraitStore, ast::m_imm, EmptyBuiltinBounds()))
BoxTraitStore, ast::m_imm, static_trait_bound))
}
75 changes: 50 additions & 25 deletions src/librustc/middle/typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
ty::BoxTraitStore
}
};
let bounds = conv_builtin_bounds(this.tcx(), bounds);
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
return ty::mk_trait(tcx,
result.def_id,
copy result.substs,
Expand Down Expand Up @@ -386,7 +386,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
bf.abis, &bf.lifetimes, &bf.decl))
}
ast::ty_closure(ref f) => {
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds);
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
// Use corresponding trait store to figure out default bounds
// if none were specified.
ast::BorrowedSigil => ty::RegionTraitStore(ty::re_empty), // dummy region
ast::OwnedSigil => ty::UniqTraitStore,
ast::ManagedSigil => ty::BoxTraitStore,
});
let fn_decl = ty_of_closure(this,
rscope,
f.sigil,
Expand All @@ -411,7 +417,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
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() =>
_ if bounds.is_some() =>
tcx.sess.span_err(ast_ty.span,
"kind bounds can only be used on trait types"),
_ => { },
Expand Down Expand Up @@ -741,41 +747,60 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
}
}

fn conv_builtin_bounds(tcx: ty::ctxt,
ast_bounds: &OptVec<ast::TyParamBound>)
fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBound>>,
store: ty::TraitStore)
-> ty::BuiltinBounds {
//! Converts a list of bounds from the AST into a `BuiltinBounds`
//! struct. Reports an error if any of the bounds that appear
//! in the AST refer to general traits and not the built-in traits
//! like `Copy` or `Owned`. Used to translate the bounds that
//! appear in closure and trait types, where only builtin bounds are
//! legal.
let mut builtin_bounds = ty::EmptyBuiltinBounds();
for ast_bounds.iter().advance |ast_bound| {
match *ast_bound {
ast::TraitTyParamBound(b) => {
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
ast::def_trait(trait_did) => {
if try_add_builtin_trait(tcx,
trait_did,
&mut builtin_bounds) {
loop; // success
//! If no bounds were specified, we choose a "default" bound based on
//! the allocation type of the fn/trait, as per issue #7264. The user can
//! override this with an empty bounds list, e.g. "~fn:()" or "~Trait:".
match (ast_bounds, store) {
(&Some(ref bound_vec), _) => {
let mut builtin_bounds = ty::EmptyBuiltinBounds();
for bound_vec.iter().advance |ast_bound| {
match *ast_bound {
ast::TraitTyParamBound(b) => {
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
ast::def_trait(trait_did) => {
if try_add_builtin_trait(tcx,
trait_did,
&mut builtin_bounds) {
loop; // success
}
}
_ => { }
}
tcx.sess.span_fatal(
b.path.span,
fmt!("only the builtin traits can be used \
as closure or object bounds"));
}
ast::RegionTyParamBound => {
builtin_bounds.add(ty::BoundStatic);
}
_ => { }
}
tcx.sess.span_fatal(
b.path.span,
fmt!("only the builtin traits can be used \
as closure or object bounds"));
}
ast::RegionTyParamBound => {
builtin_bounds.add(ty::BoundStatic);
}
builtin_bounds
},
// ~Trait is sugar for ~Trait:Owned.
(&None, ty::UniqTraitStore) => {
let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundOwned); set
}
// @Trait is sugar for @Trait:'static.
// &'static Trait is sugar for &'static Trait:'static.
(&None, ty::BoxTraitStore) |
(&None, ty::RegionTraitStore(ty::re_static)) => {
let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundStatic); set
}
// &'r Trait is sugar for &'r Trait:<no-bounds>.
(&None, ty::RegionTraitStore(*)) => ty::EmptyBuiltinBounds(),
}
builtin_bounds
}

pub fn try_add_builtin_trait(tcx: ty::ctxt,
Expand Down
8 changes: 6 additions & 2 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,11 @@ pub struct TyClosure {
purity: purity,
onceness: Onceness,
decl: fn_decl,
bounds: OptVec<TyParamBound>
// Optional optvec distinguishes between "fn()" and "fn:()" so we can
// implement issue #7264. None means "fn()", which means infer a default
// bound based on pointer sigil during typeck. Some(Empty) means "fn:()",
// which means use no bounds (e.g., not even Owned on a ~fn()).
bounds: Option<OptVec<TyParamBound>>,
}

#[deriving(Eq, Encodable, Decodable)]
Expand All @@ -795,7 +799,7 @@ pub enum ty_ {
ty_closure(@TyClosure),
ty_bare_fn(@TyBareFn),
ty_tup(~[@Ty]),
ty_path(@Path, @OptVec<TyParamBound>, node_id),
ty_path(@Path, @Option<OptVec<TyParamBound>>, node_id), // for #7264; see above
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
Expand Down
10 changes: 5 additions & 5 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,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, @OptVec<ast::TyParamBound>) -> @ast::Ty;
fn ty_path(&self, @ast::Path, @Option<OptVec<ast::TyParamBound>>) -> @ast::Ty;
fn ty_ident(&self, span: span, idents: ast::ident) -> @ast::Ty;

fn ty_rptr(&self, span: span,
Expand Down Expand Up @@ -265,7 +265,7 @@ impl AstBuilder for @ExtCtxt {
}
}

fn ty_path(&self, path: @ast::Path, bounds: @OptVec<ast::TyParamBound>)
fn ty_path(&self, path: @ast::Path, bounds: @Option<OptVec<ast::TyParamBound>>)
-> @ast::Ty {
self.ty(path.span,
ast::ty_path(path, bounds, self.next_id()))
Expand All @@ -275,7 +275,7 @@ impl AstBuilder for @ExtCtxt {
// 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), @opt_vec::Empty)
self.ty_path(self.path_ident(span, ident), @None)
}

fn ty_rptr(&self,
Expand Down Expand Up @@ -306,7 +306,7 @@ impl AstBuilder for @ExtCtxt {
],
None,
~[ ty ]),
@opt_vec::Empty)
@None)
}

fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field {
Expand Down Expand Up @@ -344,7 +344,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]), @opt_vec::Empty)))
self.path_global(dummy_sp(), ~[p.ident]), @None)))
}

fn strip_bounds(&self, generics: &Generics) -> Generics {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/deriving/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ 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::Empty);
@None);

let doc_attr = cx.attribute(
span,
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/ext/deriving/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl<'self> Path<'self> {
self_generics: &Generics)
-> @ast::Ty {
cx.ty_path(self.to_path(cx, span,
self_ty, self_generics), @opt_vec::Empty)
self_ty, self_generics), @None)
}
pub fn to_path(&self,
cx: @ExtCtxt,
Expand Down Expand Up @@ -143,7 +143,7 @@ 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),
@opt_vec::Empty)
@None)
}
Tuple(ref fields) => {
let ty = if fields.is_empty() {
Expand Down
20 changes: 10 additions & 10 deletions src/libsyntax/ext/pipes/pipec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,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)), @opt_vec::Empty);
.add_tys(cx.ty_vars(&this.generics.ty_params)), @None);
let args_ast = vec::append(
~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)],
args_ast);
Expand Down Expand Up @@ -115,7 +115,7 @@ impl gen_send for message {

let mut rty = cx.ty_path(path(~[next.data_name()],
span)
.add_tys(copy next_state.tys), @opt_vec::Empty);
.add_tys(copy next_state.tys), @None);
if try {
rty = cx.ty_option(rty);
}
Expand Down Expand Up @@ -144,7 +144,7 @@ impl gen_send for message {
cx.ty_path(
path(~[this.data_name()], span)
.add_tys(cx.ty_vars(
&this.generics.ty_params)), @opt_vec::Empty))],
&this.generics.ty_params)), @None))],
args_ast);

let message_args = if arg_names.len() == 0 {
Expand Down Expand Up @@ -190,7 +190,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)), @opt_vec::Empty)
.add_tys(cx.ty_vars(&self.get_generics().ty_params)), @None)
}
}

Expand Down Expand Up @@ -224,7 +224,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), @opt_vec::Empty))
.add_tys(copy next_state.tys), @None))
}
None => tys
};
Expand Down Expand Up @@ -277,8 +277,8 @@ impl to_type_decls for state {
self.data_name()],
dummy_sp())
.add_tys(cx.ty_vars(
&self.generics.ty_params)), @opt_vec::Empty)),
@opt_vec::Empty),
&self.generics.ty_params)), @None)),
@None),
cx.strip_bounds(&self.generics)));
}
else {
Expand All @@ -297,8 +297,8 @@ impl to_type_decls for state {
self.data_name()],
dummy_sp())
.add_tys(cx.ty_vars_global(
&self.generics.ty_params)), @opt_vec::Empty),
self.proto.buffer_ty_path(cx)]), @opt_vec::Empty),
&self.generics.ty_params)), @None),
self.proto.buffer_ty_path(cx)]), @None),
cx.strip_bounds(&self.generics)));
};
items
Expand Down Expand Up @@ -383,7 +383,7 @@ impl gen_init for protocol {
cx.ty_path(path(~[cx.ident_of("super"),
cx.ident_of("__Buffer")],
copy self.span)
.add_tys(cx.ty_vars_global(&params)), @opt_vec::Empty)
.add_tys(cx.ty_vars_global(&params)), @None)
}

fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item {
Expand Down
3 changes: 1 addition & 2 deletions src/libsyntax/ext/pipes/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ 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 }
Expand Down Expand Up @@ -100,7 +99,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)), @opt_vec::Empty)
cx.ty_vars(&self.generics.ty_params)), @None)
}

/// Iterate over the states that can be reached in one message
Expand Down
11 changes: 8 additions & 3 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,12 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
span: fld.new_span(f.span),
}
}
fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold)
-> Option<OptVec<TyParamBound>> {
do b.map |bounds| {
do bounds.map |bound| { fold_ty_param_bound(bound, fld) }
}
}
match *t {
ty_nil | ty_bot | ty_infer => copy *t,
ty_box(ref mt) => ty_box(fold_mt(mt, fld)),
Expand All @@ -664,7 +670,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
purity: f.purity,
region: f.region,
onceness: f.onceness,
bounds: f.bounds.map(|x| fold_ty_param_bound(x, fld)),
bounds: fold_opt_bounds(&f.bounds, fld),
decl: fold_fn_decl(&f.decl, fld),
lifetimes: copy f.lifetimes,
})
Expand All @@ -679,8 +685,7 @@ 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, bounds, id) =>
ty_path(fld.fold_path(path),
@bounds.map(|x| fold_ty_param_bound(x, fld)), fld.new_id(id)),
ty_path(fld.fold_path(path), @fold_opt_bounds(bounds, fld), fld.new_id(id)),
ty_fixed_length_vec(ref mt, e) => {
ty_fixed_length_vec(
fold_mt(mt, fld),
Expand Down
Loading

0 comments on commit 7b96878

Please sign in to comment.