]> git.lizzy.rs Git - rust.git/commitdiff
Infer default static/Owned bounds for unbounded heap fns/traits (#7264)
authorBen Blum <bblum@andrew.cmu.edu>
Thu, 20 Jun 2013 22:23:25 +0000 (18:23 -0400)
committerBen Blum <bblum@andrew.cmu.edu>
Wed, 26 Jun 2013 22:14:43 +0000 (18:14 -0400)
25 files changed:
src/librustc/metadata/encoder.rs
src/librustc/middle/kind.rs
src/librustc/middle/resolve.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/astconv.rs
src/libsyntax/ast.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/deriving/generic.rs
src/libsyntax/ext/deriving/ty.rs
src/libsyntax/ext/pipes/pipec.rs
src/libsyntax/ext/pipes/proto.rs
src/libsyntax/fold.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs
src/test/compile-fail/closure-bounds-subtype.rs
src/test/compile-fail/trait-bounds-cant-coerce.rs
src/test/compile-fail/trait-bounds-sugar.rs [new file with mode: 0644]
src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs
src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs
src/test/run-pass/kindck-owned-trait-contains-1.rs
src/test/run-pass/regions-trait.rs
src/test/run-pass/trait-bounds-basic.rs

index 9c28da10e40d5abcd58cd8aeeef39c8474ecc4c3..cb47c88d3d4fc843d82839223c57eeb9204fadff 100644 (file)
@@ -959,7 +959,7 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
         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));
             }
index b0b2a16cf89392d465d262a96fdaabe436c187bf..1c669631244c36a7c0294d480e3198d266f6dce3 100644 (file)
@@ -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 =
index a8626ca89aa898a15a089f539b4e4605ecacbf97..e06fd8f971791796f7e7f405a271d47beb756e9e 100644 (file)
@@ -4195,15 +4195,19 @@ pub fn resolve_type(@mut self, ty: @Ty, visitor: ResolveVisitor) {
                     }
                 }
 
-                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));
             }
 
index 328b331ea63ed40a2a42d45b3f357cc32ebd0585..a43025e4ff9791ad93a5fc5286f28af56b064d7d 100644 (file)
@@ -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))
 }
index 5e6574850f1b8ca1aa94617b37ca6d8a73887e39..997061a61ba636f30b73b3be783d6788f0f27a6d 100644 (file)
@@ -303,7 +303,7 @@ fn mk_pointer<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,
@@ -386,7 +386,13 @@ fn check_path_args(tcx: ty::ctxt,
                                             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,
@@ -411,7 +417,7 @@ fn check_path_args(tcx: ty::ctxt,
         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"),
             _ => { },
@@ -741,8 +747,8 @@ 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
@@ -750,32 +756,51 @@ fn conv_builtin_bounds(tcx: ty::ctxt,
     //! 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,
index 90b2f131b00ee7efc00d8ac6d2eabb60402eaeb0..1a7094acf7e4ec279ef701f49d4db5996747d21d 100644 (file)
@@ -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)]
@@ -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
index 02d5991e1a7bb762fedc9569038d8ba334eac97c..2c1b4cfc59155bec02f42ed2a5f1402c999c4cf3 100644 (file)
@@ -46,7 +46,7 @@ fn path_all(&self, sp: span,
     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,
@@ -265,7 +265,7 @@ fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty {
         }
     }
 
-    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()))
@@ -275,7 +275,7 @@ fn ty_path(&self, path: @ast::Path, bounds: @OptVec<ast::TyParamBound>)
     // 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,
@@ -306,7 +306,7 @@ fn ty_option(&self, ty: @ast::Ty) -> @ast::Ty {
                           ],
                           None,
                           ~[ ty ]),
-            @opt_vec::Empty)
+            @None)
     }
 
     fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field {
@@ -344,7 +344,7 @@ fn ty_vars(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] {
     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 {
index 17bbe7a333e659e0f6740b660bf251ba8187cbd2..10d9f878bc45187234357d598d4ffbbbf94ce662 100644 (file)
@@ -357,7 +357,7 @@ fn create_derived_impl(&self, cx: @ExtCtxt, span: span,
         // 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,
index 9da6bf27eadaecd75c8bcc785fd015f676ce83f2..2f21eba11d7e2b172f917f4a76fe2530d5ed7f3a 100644 (file)
@@ -63,7 +63,7 @@ pub fn to_ty(&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,
@@ -143,7 +143,7 @@ pub fn to_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() {
index a75a20a0fa97c2cd04270336c136eee1609b359b..2c5ec0909d9514416155fc3660054f10040be52f 100644 (file)
@@ -59,7 +59,7 @@ fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item {
 
             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);
@@ -115,7 +115,7 @@ fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item {
 
             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);
             }
@@ -144,7 +144,7 @@ fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item {
                              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 {
@@ -190,7 +190,7 @@ fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item {
 
     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)
     }
 }
 
@@ -224,7 +224,7 @@ fn to_type_decls(&self, cx: @ExtCtxt) -> ~[@ast::item] {
                                 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
             };
@@ -277,8 +277,8 @@ fn to_endpoint_decls(&self, cx: @ExtCtxt,
                                    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 {
@@ -297,8 +297,8 @@ fn to_endpoint_decls(&self, cx: @ExtCtxt,
                                    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
@@ -383,7 +383,7 @@ fn buffer_ty_path(&self, cx: @ExtCtxt) -> @ast::Ty {
         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 {
index e86ced847d74adcd5f2cfaccea03c33bf16053ce..0525c6664780e4b7ba457fef1fd62261e936eec0 100644 (file)
@@ -13,7 +13,6 @@
 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 }
@@ -100,7 +99,7 @@ pub fn data_name(&self) -> ast::ident {
     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
index 2c7c335a84109064b2d79572b44c903323cd94a5..2fc111da453cf1023a5059dc470c2ce2186db59d 100644 (file)
@@ -651,6 +651,12 @@ fn fold_field(f: ty_field, fld: @ast_fold) -> ty_field {
             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)),
@@ -664,7 +670,7 @@ fn fold_field(f: ty_field, fld: @ast_fold) -> ty_field {
                 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,
             })
@@ -679,8 +685,7 @@ fn fold_field(f: ty_field, fld: @ast_fold) -> ty_field {
         }
         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),
index d54c64e7ee60ecd32a036fc75e312b6aec0398df..6dd8d4880e3f0d69fb80b8fc0de85d8539263d4e 100644 (file)
@@ -490,7 +490,7 @@ fn parser_done(p: Parser){
                                         idents:~[str_to_ident("int")],
                                         rp: None,
                                         types: ~[]},
-                                                       @opt_vec::Empty, 2),
+                                                       @None, 2),
                                     span:sp(4,7)},
                        pat: @ast::pat{id:1,
                                       node: ast::pat_ident(ast::bind_infer,
@@ -526,7 +526,7 @@ fn parser_done(p: Parser){
                                         idents:~[str_to_ident("int")],
                                         rp: None,
                                         types: ~[]},
-                                                       @opt_vec::Empty, 2),
+                                                       @None, 2),
                                                 span:sp(10,13)},
                                     pat: @ast::pat{id:1, // fixme
                                                    node: ast::pat_ident(
index b10005aeaf1a0734485f115443dbd6277e117d10..d67771fc43547dac4cb01956c3d8d9f604ac35d5 100644 (file)
@@ -1047,8 +1047,8 @@ pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
 
     // 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;
+    pub fn parse_type_path(&self) -> (@ast::Path, Option<OptVec<TyParamBound>>) {
+        let mut bounds = None;
         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.
@@ -2884,9 +2884,13 @@ fn parse_optional_onceness(&self) -> ast::Onceness {
     // matches optbounds = ( ( : ( boundseq )? )? )
     // where   boundseq  = ( bound + boundseq ) | bound
     // and     bound     = 'static | ty
-    fn parse_optional_ty_param_bounds(&self) -> OptVec<TyParamBound> {
+    // Returns "None" if there's no colon (e.g. "T");
+    // Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:")
+    // Returns "Some(stuff)" otherwise (e.g. "T:stuff").
+    // NB: The None/Some distinction is important for issue #7264.
+    fn parse_optional_ty_param_bounds(&self) -> Option<OptVec<TyParamBound>> {
         if !self.eat(&token::COLON) {
-            return opt_vec::Empty;
+            return None;
         }
 
         let mut result = opt_vec::Empty;
@@ -2935,13 +2939,15 @@ fn parse_optional_ty_param_bounds(&self) -> OptVec<TyParamBound> {
             }
         }
 
-        return result;
+        return Some(result);
     }
 
     // matches typaram = IDENT optbounds
     fn parse_ty_param(&self) -> TyParam {
         let ident = self.parse_ident();
-        let bounds = @self.parse_optional_ty_param_bounds();
+        let opt_bounds = self.parse_optional_ty_param_bounds();
+        // For typarams we don't care about the difference b/w "<T>" and "<T:>".
+        let bounds = @opt_bounds.get_or_default(opt_vec::Empty);
         ast::TyParam { ident: ident, id: self.get_id(), bounds: bounds }
     }
 
@@ -3288,7 +3294,7 @@ fn parse_item_impl(&self, visibility: ast::visibility) -> item_info {
         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, @opt_vec::Empty, node_id) => {
+                ty_path(path, @None, node_id) => {
                     Some(@trait_ref {
                         path: path,
                         ref_id: node_id
index 277cc6208fb08177cc307797f0fd036ae8e7fda5..0be8c31647f63499cfd0f4b5743dfe3c089efd8f 100644 (file)
@@ -1488,7 +1488,7 @@ pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) {
 }
 
 fn print_path_(s: @ps, path: @ast::Path, colons_before_params: bool,
-               opt_bounds: Option<@OptVec<ast::TyParamBound>>) {
+               opt_bounds: &Option<OptVec<ast::TyParamBound>>) {
     maybe_print_comment(s, path.span.lo);
     if path.global { word(s.s, "::"); }
     let mut first = true;
@@ -1496,7 +1496,7 @@ 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| {
+    do opt_bounds.map |bounds| {
         print_bounds(s, bounds);
     };
     if path.rp.is_some() || !path.types.is_empty() {
@@ -1520,12 +1520,12 @@ 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)
+    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))
+                          bounds: &Option<OptVec<ast::TyParamBound>>) {
+    print_path_(s, path, false, bounds)
 }
 
 pub fn print_irrefutable_pat(s: @ps, pat: @ast::pat) {
@@ -1737,7 +1737,7 @@ pub fn print_fn_block_args(s: @ps, decl: &ast::fn_decl) {
     maybe_print_comment(s, decl.output.span.lo);
 }
 
-pub fn print_bounds(s: @ps, bounds: @OptVec<ast::TyParamBound>) {
+pub fn print_bounds(s: @ps, bounds: &OptVec<ast::TyParamBound>) {
     if !bounds.is_empty() {
         word(s.s, ":");
         let mut first = true;
index 9b816ce5e5b7cf0bdb831ff13befa2e45558a832..f0a993dbb94233e5693db631ec9f8b5129d4a69b 100644 (file)
@@ -246,7 +246,9 @@ 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, (copy e, v));
-            visit_ty_param_bounds(&f.bounds, (e, v));
+            do f.bounds.map |bounds| {
+                visit_ty_param_bounds(bounds, (copy e, v));
+            };
         },
         ty_bare_fn(ref f) => {
             for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
@@ -254,7 +256,9 @@ pub fn visit_ty<E: Copy>(t: @Ty, (e, v): (E, vt<E>)) {
         },
         ty_path(p, bounds, _) => {
             visit_path(p, (copy e, v));
-            visit_ty_param_bounds(bounds, (e, v));
+            do bounds.map |bounds| {
+                visit_ty_param_bounds(bounds, (copy e, v));
+            };
         },
         ty_fixed_length_vec(ref mt, ex) => {
             (v.visit_ty)(mt.ty, (copy e, v));
index c3c8467233c4ddbfc28b1b1c739d92be4b7ad544..098a395f017445133027e607346ca1680b52e10c 100644 (file)
@@ -12,7 +12,7 @@ struct X {
     field: @fn:Copy(),
 }
 
-fn foo(blk: @fn()) -> X {
+fn foo(blk: @fn:()) -> X {
     return X { field: blk }; //~ ERROR expected bounds `Copy` but found no bounds
 }
 
index a975349e7302289ce672f33226eb93d0e13093a2..887346e35e5eae27e9352f51d3b933433106111a 100644 (file)
@@ -1,5 +1,5 @@
 
-fn take_any(_: &fn()) {
+fn take_any(_: &fn:()) {
 }
 
 fn take_copyable(_: &fn:Copy()) {
@@ -11,7 +11,7 @@ fn take_copyable_owned(_: &fn:Copy+Owned()) {
 fn take_const_owned(_: &fn:Const+Owned()) {
 }
 
-fn give_any(f: &fn()) {
+fn give_any(f: &fn:()) {
     take_any(f);
     take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds
     take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found no bounds
index 88c2d49174733b1888269c063eaeae09bc239eb3..adaea1de9bd0f87d13636e89ba6a816481c6794a 100644 (file)
@@ -21,7 +21,7 @@ fn c(x: ~Foo:Const+Owned) {
     b(x); //~ ERROR expected bounds `Copy+Owned`
 }
 
-fn d(x: ~Foo) {
+fn d(x: ~Foo:) {
     a(x); //~ ERROR found no bounds
 }
 
diff --git a/src/test/compile-fail/trait-bounds-sugar.rs b/src/test/compile-fail/trait-bounds-sugar.rs
new file mode 100644 (file)
index 0000000..8c641f4
--- /dev/null
@@ -0,0 +1,37 @@
+// 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.
+
+// Tests for "default" bounds inferred for traits with no bounds list.
+
+trait Foo {
+}
+
+fn a(_x: ~Foo) { // should be same as ~Foo:Owned
+}
+
+fn b(_x: @Foo) { // should be same as ~Foo:'static
+}
+
+fn c(_x: &'static Foo) { // should be same as &'static Foo:'static
+}
+
+fn d(x: ~Foo:Const) {
+    a(x); //~ ERROR expected bounds `Owned`
+}
+
+fn e(x: @Foo:Const) {
+    b(x); //~ ERROR expected bounds `'static`
+}
+
+fn f(x: &'static Foo:Const) {
+    c(x); //~ ERROR expected bounds `'static`
+}
+
+fn main() { }
index f39c914916ff7b812084f8d81fb2254b7a0162cf..171f2bbb872e091cec0597e1bd2401e71049b65d 100644 (file)
@@ -12,7 +12,7 @@
 
 // Tests correct copying of heap closures' environments.
 
-fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) {
+fn foo(x: ~fn:Copy()) -> (~fn:(), ~fn:()) {
     (copy x, x)
 }
 fn main() {
index 2fdce4e5c7cdfbb89e5c89ee309fd9cad8341bed..9bfda034878ba28b6afd1361a8cb9833196e4862 100644 (file)
@@ -15,7 +15,7 @@
 fn bar<T: Copy>(x: T) -> (T, T) {
     (copy x, x)
 }
-fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) {
+fn foo(x: ~fn:Copy()) -> (~fn:(), ~fn:()) {
     bar(x)
 }
 fn main() {
index c51094d26c88febea99babd915cc58d095e40dee..e733400527b286353ce159c1d4311fad082846b6 100644 (file)
@@ -14,9 +14,9 @@ impl<A:Copy> repeat<A> for @A {
     fn get(&self) -> A { copy **self }
 }
 
-fn repeater<A:Copy>(v: @A) -> @repeat<A> {
+fn repeater<A:Copy>(v: @A) -> @repeat:<A> {
     // Note: owned kind is not necessary as A appears in the trait type
-    @v as @repeat<A> // No
+    @v as @repeat:<A> // No
 }
 
 pub fn main() {
index b5b13efa634fa523e66b673d6e931f71be9cbde4..049d5305ca427f68b0cad94024e3c0e4bdb26606 100644 (file)
@@ -22,7 +22,7 @@ fn get_ctxt(&self) -> &'self Ctxt {
     }
 }
 
-fn get_v(gc: @get_ctxt) -> uint {
+fn get_v(gc: @get_ctxt:) -> uint {
     gc.get_ctxt().v
 }
 
@@ -30,5 +30,5 @@ pub fn main() {
     let ctxt = Ctxt { v: 22 };
     let hc = HasCtxt { c: &ctxt };
 
-    assert_eq!(get_v(@hc as @get_ctxt), 22);
+    assert_eq!(get_v(@hc as @get_ctxt:), 22);
 }
index b9251c038afaa291f845c11f23c2a5bdb7c0fb15..5bfbf84d8acacb585b5aa7d5151ddb6ab8be8fc5 100644 (file)
@@ -11,7 +11,7 @@
 trait Foo {
 }
 
-fn a(_x: ~Foo) {
+fn a(_x: ~Foo:) {
 }
 
 fn b(_x: ~Foo:Owned) {
@@ -25,4 +25,8 @@ fn d(x: ~Foo:Owned+Copy) {
     b(x);
 }
 
+fn e(x: ~Foo) { // sugar for ~Foo:Owned
+    b(x);
+}
+
 fn main() { }