about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-06-11 12:14:38 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-06-13 13:53:34 -0700
commit9b9ef442337ee3b9a29449a0792ae2eeb0480d0c (patch)
tree0be19c2428e4bb08c91346b0c74366e2e9b0a510
parent03ec8e5cc91b3b6b6ab98ef70aa63a0965c5f6c1 (diff)
downloadrust-9b9ef442337ee3b9a29449a0792ae2eeb0480d0c.tar.gz
rust-9b9ef442337ee3b9a29449a0792ae2eeb0480d0c.zip
libsyntax: Allow `+` to separate trait bounds from objects.
RFC #27.

After a snapshot, the old syntax will be removed.

This can break some code that looked like `foo as &Trait:Send`. Now you
will need to write `foo as (&Trait+Send)`.

Closes #12778.

[breaking-change]
-rw-r--r--src/librustc/middle/typeck/astconv.rs1
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs1
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ast_util.rs1
-rw-r--r--src/libsyntax/fold.rs1
-rw-r--r--src/libsyntax/parse/parser.rs137
-rw-r--r--src/libsyntax/print/pprust.rs27
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/test/auxiliary/plugin_crate_outlive_expansion_phase.rs4
-rw-r--r--src/test/compile-fail/issue-7013.rs2
-rw-r--r--src/test/compile-fail/kindck-copy.rs8
-rw-r--r--src/test/compile-fail/kindck-send.rs10
-rw-r--r--src/test/compile-fail/trait-bounds-cant-coerce.rs6
-rw-r--r--src/test/compile-fail/trait-bounds-sugar.rs8
-rw-r--r--src/test/run-fail/fail-macro-any.rs2
-rw-r--r--src/test/run-pass/alignment-gep-tup-like-1.rs2
-rw-r--r--src/test/run-pass/as-precedence.rs18
-rw-r--r--src/test/run-pass/capturing-logging.rs2
-rw-r--r--src/test/run-pass/close-over-big-then-small-data.rs4
-rw-r--r--src/test/run-pass/trait-bounds-basic.rs10
-rw-r--r--src/test/run-pass/trait-bounds-in-arc.rs14
-rw-r--r--src/test/run-pass/trait-cast.rs6
-rw-r--r--src/test/run-pass/trait-contravariant-self.rs6
24 files changed, 176 insertions, 101 deletions
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 83c5be23816..f380004fb08 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -724,6 +724,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                                  .collect();
                 ty::mk_tup(tcx, flds)
             }
+            ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
             ast::TyBareFn(ref bf) => {
                 if bf.decl.variadic && bf.abi != abi::C {
                     tcx.sess.span_err(ast_ty.span,
diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs
index 2e02c798339..4d396ed4f6e 100644
--- a/src/librustc/middle/typeck/infer/error_reporting.rs
+++ b/src/librustc/middle/typeck/infer/error_reporting.rs
@@ -1140,6 +1140,7 @@ impl<'a> Rebuilder<'a> {
                     }
                     ast::TyTup(new_tys)
                 }
+                ast::TyParen(ref typ) => ast::TyParen(build_to(*typ, to)),
                 ref other => other.clone()
             };
             box(GC) ast::Ty { id: from.id, node: new_node, span: from.span }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index dd6cc978ae7..7e68be09f1d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -60,7 +60,7 @@ impl<T: Clean<U>, U> Clean<VecPerParamSpace<U>> for VecPerParamSpace<T> {
     }
 }
 
-impl<T: Clean<U>, U> Clean<U> for Gc<T> {
+impl<T: 'static + Clean<U>, U> Clean<U> for Gc<T> {
     fn clean(&self) -> U {
         (**self).clean()
     }
@@ -1198,6 +1198,7 @@ impl Clean<Type> for ast::Ty {
             TyClosure(ref c, region) => Closure(box c.clean(), region.clean()),
             TyProc(ref c) => Proc(box c.clean()),
             TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
+            TyParen(ref ty) => ty.clean(),
             TyBot => Bottom,
             ref x => fail!("Unimplemented type {:?}", x),
         }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 941078b158b..b8e08dab722 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -784,6 +784,8 @@ pub enum Ty_ {
     TyUnboxedFn(Gc<UnboxedFnTy>),
     TyTup(Vec<P<Ty>> ),
     TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
+    // No-op; kept solely so that we can pretty-print faithfully
+    TyParen(P<Ty>),
     TyTypeof(Gc<Expr>),
     // TyInfer means the type should be inferred instead of it having been
     // specified. This can appear anywhere in a type.
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index fcddbfa9a89..8e0a2218ea3 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -737,6 +737,7 @@ pub fn get_inner_tys(ty: P<Ty>) -> Vec<P<Ty>> {
         | ast::TyUniq(ty)
         | ast::TyFixedLengthVec(ty, _) => vec!(ty),
         ast::TyTup(ref tys) => tys.clone(),
+        ast::TyParen(ty) => get_inner_tys(ty),
         _ => Vec::new()
     }
 }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index d8c7ffe4db7..d61a79e4e80 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -192,6 +192,7 @@ pub trait Folder {
                 })
             }
             TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()),
+            TyParen(ref ty) => TyParen(self.fold_ty(*ty)),
             TyPath(ref path, ref bounds, id) => {
                 let id = self.new_id(id);
                 TyPath(self.fold_path(path),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index aaedb570955..e1a45e5643d 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -51,7 +51,7 @@ use ast::{TokenTree, TraitMethod, TraitRef, TTDelim, TTSeq, TTTok};
 use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
 use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
 use ast::{TyTypeof, TyInfer, TypeMethod};
-use ast::{TyNil, TyParam, TyParamBound, TyPath, TyPtr, TyRptr};
+use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyRptr};
 use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
 use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock};
 use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
@@ -105,7 +105,7 @@ pub enum PathParsingMode {
     /// the type parameters; e.g. `foo::bar::<'a>::Baz::<T>`
     LifetimeAndTypesWithColons,
     /// A path with a lifetime and type parameters with bounds before the last
-    /// set of type parameters only; e.g. `foo::bar<'a>::Baz:X+Y<T>` This
+    /// set of type parameters only; e.g. `foo::bar<'a>::Baz+X+Y<T>` This
     /// form does not use extra double colons.
     LifetimeAndTypesAndBounds,
 }
@@ -1015,7 +1015,14 @@ impl<'a> Parser<'a> {
         };
 
         let (inputs, variadic) = self.parse_fn_args(false, false);
-        let (_, bounds) = self.parse_optional_ty_param_bounds(false);
+        let bounds = {
+            if self.eat(&token::COLON) {
+                let (_, bounds) = self.parse_ty_param_bounds(false);
+                Some(bounds)
+            } else {
+                None
+            }
+        };
         let (ret_style, ret_ty) = self.parse_ret_ty();
         let decl = P(FnDecl {
             inputs: inputs,
@@ -1083,7 +1090,14 @@ impl<'a> Parser<'a> {
             (is_unboxed, inputs)
         };
 
-        let (region, bounds) = self.parse_optional_ty_param_bounds(true);
+        let (region, bounds) = {
+            if self.eat(&token::COLON) {
+                let (region, bounds) = self.parse_ty_param_bounds(true);
+                (region, Some(bounds))
+            } else {
+                (None, None)
+            }
+        };
 
         let (return_style, output) = self.parse_ret_ty();
         let decl = P(FnDecl {
@@ -1227,7 +1241,7 @@ impl<'a> Parser<'a> {
     // parse a possibly mutable type
     pub fn parse_mt(&mut self) -> MutTy {
         let mutbl = self.parse_mutability();
-        let t = self.parse_ty(false);
+        let t = self.parse_ty(true);
         MutTy { ty: t, mutbl: mutbl }
     }
 
@@ -1238,7 +1252,7 @@ impl<'a> Parser<'a> {
         let mutbl = self.parse_mutability();
         let id = self.parse_ident();
         self.expect(&token::COLON);
-        let ty = self.parse_ty(false);
+        let ty = self.parse_ty(true);
         let hi = ty.span.hi;
         ast::TypeField {
             ident: id,
@@ -1261,7 +1275,7 @@ impl<'a> Parser<'a> {
                     })
                 )
             } else {
-                (Return, self.parse_ty(false))
+                (Return, self.parse_ty(true))
             }
         } else {
             let pos = self.span.lo;
@@ -1276,10 +1290,11 @@ impl<'a> Parser<'a> {
         }
     }
 
-    // parse a type.
-    // Useless second parameter for compatibility with quasiquote macros.
-    // Bleh!
-    pub fn parse_ty(&mut self, _: bool) -> P<Ty> {
+    /// Parse a type.
+    ///
+    /// The second parameter specifies whether the `+` binary operator is
+    /// allowed in the type grammar.
+    pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
         maybe_whole!(no_clone self, NtTy);
 
         let lo = self.span.lo;
@@ -1293,12 +1308,12 @@ impl<'a> Parser<'a> {
                 // (t) is a parenthesized ty
                 // (t,) is the type of a tuple with only one field,
                 // of type t
-                let mut ts = vec!(self.parse_ty(false));
+                let mut ts = vec!(self.parse_ty(true));
                 let mut one_tuple = false;
                 while self.token == token::COMMA {
                     self.bump();
                     if self.token != token::RPAREN {
-                        ts.push(self.parse_ty(false));
+                        ts.push(self.parse_ty(true));
                     }
                     else {
                         one_tuple = true;
@@ -1307,17 +1322,17 @@ impl<'a> Parser<'a> {
 
                 if ts.len() == 1 && !one_tuple {
                     self.expect(&token::RPAREN);
-                    return *ts.get(0)
+                    TyParen(*ts.get(0))
+                } else {
+                    let t = TyTup(ts);
+                    self.expect(&token::RPAREN);
+                    t
                 }
-
-                let t = TyTup(ts);
-                self.expect(&token::RPAREN);
-                t
             }
         } else if self.token == token::AT {
             // MANAGED POINTER
             self.bump();
-            TyBox(self.parse_ty(false))
+            TyBox(self.parse_ty(plus_allowed))
         } else if self.token == token::TILDE {
             // OWNED POINTER
             self.bump();
@@ -1326,7 +1341,7 @@ impl<'a> Parser<'a> {
                     self.obsolete(self.last_span, ObsoleteOwnedVector),
                 _ => self.obsolete(self.last_span, ObsoleteOwnedType),
             };
-            TyUniq(self.parse_ty(false))
+            TyUniq(self.parse_ty(true))
         } else if self.token == token::BINOP(token::STAR) {
             // STAR POINTER (bare pointer?)
             self.bump();
@@ -1334,7 +1349,7 @@ impl<'a> Parser<'a> {
         } else if self.token == token::LBRACKET {
             // VECTOR
             self.expect(&token::LBRACKET);
-            let t = self.parse_ty(false);
+            let t = self.parse_ty(true);
 
             // Parse the `, ..e` in `[ int, ..e ]`
             // where `e` is a const expression
@@ -1377,10 +1392,15 @@ impl<'a> Parser<'a> {
         } else if self.token == token::MOD_SEP
             || is_ident_or_path(&self.token) {
             // NAMED TYPE
+            let mode = if plus_allowed {
+                LifetimeAndTypesAndBounds
+            } else {
+                LifetimeAndTypesWithoutColons
+            };
             let PathAndBounds {
                 path,
                 bounds
-            } = self.parse_path(LifetimeAndTypesAndBounds);
+            } = self.parse_path(mode);
             TyPath(path, bounds, ast::DUMMY_NODE_ID)
         } else if self.eat(&token::UNDERSCORE) {
             // TYPE TO BE INFERRED
@@ -1438,7 +1458,7 @@ impl<'a> Parser<'a> {
                                    special_idents::invalid)
         };
 
-        let t = self.parse_ty(false);
+        let t = self.parse_ty(true);
 
         Arg {
             ty: t,
@@ -1456,7 +1476,7 @@ impl<'a> Parser<'a> {
     pub fn parse_fn_block_arg(&mut self) -> Arg {
         let pat = self.parse_pat();
         let t = if self.eat(&token::COLON) {
-            self.parse_ty(false)
+            self.parse_ty(true)
         } else {
             P(Ty {
                 id: ast::DUMMY_NODE_ID,
@@ -1611,9 +1631,19 @@ impl<'a> Parser<'a> {
             }
         }
 
-        // Next, parse a colon and bounded type parameters, if applicable.
+        // Next, parse a plus and bounded type parameters, if applicable.
+        //
+        // NOTE(stage0, pcwalton): Remove `token::COLON` after a snapshot.
         let bounds = if mode == LifetimeAndTypesAndBounds {
-            let (_, bounds) = self.parse_optional_ty_param_bounds(false);
+            let bounds = {
+                if self.eat(&token::BINOP(token::PLUS)) ||
+                        self.eat(&token::COLON) {
+                    let (_, bounds) = self.parse_ty_param_bounds(false);
+                    Some(bounds)
+                } else {
+                    None
+                }
+            };
             bounds
         } else {
             None
@@ -2438,7 +2468,7 @@ impl<'a> Parser<'a> {
             }
             None => {
                 if as_prec > min_prec && self.eat_keyword(keywords::As) {
-                    let rhs = self.parse_ty(true);
+                    let rhs = self.parse_ty(false);
                     let _as = self.mk_expr(lhs.span.lo,
                                            rhs.span.hi,
                                            ExprCast(lhs, rhs));
@@ -3067,7 +3097,9 @@ impl<'a> Parser<'a> {
             node: TyInfer,
             span: mk_sp(lo, lo),
         });
-        if self.eat(&token::COLON) { ty = self.parse_ty(false); }
+        if self.eat(&token::COLON) {
+            ty = self.parse_ty(true);
+        }
         let init = self.parse_initializer();
         box(GC) ast::Local {
             ty: ty,
@@ -3095,7 +3127,7 @@ impl<'a> Parser<'a> {
         }
         let name = self.parse_ident();
         self.expect(&token::COLON);
-        let ty = self.parse_ty(false);
+        let ty = self.parse_ty(true);
         spanned(lo, self.last_span.hi, ast::StructField_ {
             kind: NamedField(name, pr),
             id: ast::DUMMY_NODE_ID,
@@ -3427,7 +3459,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    // matches optbounds = ( ( : ( boundseq )? )? )
+    // matches bounds    = ( boundseq )?
     // where   boundseq  = ( bound + boundseq ) | bound
     // and     bound     = 'static | ty
     // Returns "None" if there's no colon (e.g. "T");
@@ -3439,13 +3471,9 @@ impl<'a> Parser<'a> {
     // AST doesn't support arbitrary lifetimes in bounds on type parameters. In
     // the future, this flag should be removed, and the return value of this
     // function should be Option<~[TyParamBound]>
-    fn parse_optional_ty_param_bounds(&mut self, allow_any_lifetime: bool)
-        -> (Option<ast::Lifetime>, Option<OwnedSlice<TyParamBound>>)
-    {
-        if !self.eat(&token::COLON) {
-            return (None, None);
-        }
-
+    fn parse_ty_param_bounds(&mut self, allow_any_lifetime: bool)
+                             -> (Option<ast::Lifetime>,
+                                 OwnedSlice<TyParamBound>) {
         let mut ret_lifetime = None;
         let mut result = vec!();
         loop {
@@ -3489,7 +3517,7 @@ impl<'a> Parser<'a> {
             }
         }
 
-        return (ret_lifetime, Some(OwnedSlice::from_vec(result)));
+        return (ret_lifetime, OwnedSlice::from_vec(result));
     }
 
     // matches typaram = type? IDENT optbounds ( EQ ty )?
@@ -3497,13 +3525,20 @@ impl<'a> Parser<'a> {
         let sized = self.parse_sized();
         let span = self.span;
         let ident = self.parse_ident();
-        let (_, opt_bounds) = self.parse_optional_ty_param_bounds(false);
+        let opt_bounds = {
+            if self.eat(&token::COLON) {
+                let (_, bounds) = self.parse_ty_param_bounds(false);
+                Some(bounds)
+            } else {
+                None
+            }
+        };
         // For typarams we don't care about the difference b/w "<T>" and "<T:>".
         let bounds = opt_bounds.unwrap_or_default();
 
         let default = if self.token == token::EQ {
             self.bump();
-            Some(self.parse_ty(false))
+            Some(self.parse_ty(true))
         }
         else { None };
 
@@ -3548,7 +3583,7 @@ impl<'a> Parser<'a> {
             Some(token::COMMA),
             |p| {
                 p.forbid_lifetime();
-                p.parse_ty(false)
+                p.parse_ty(true)
             }
         );
         (lifetimes, result.into_vec())
@@ -3804,7 +3839,7 @@ impl<'a> Parser<'a> {
             }
         };
         let output = if self.eat(&token::RARROW) {
-            self.parse_ty(false)
+            self.parse_ty(true)
         } else {
             P(Ty {
                 id: ast::DUMMY_NODE_ID,
@@ -3830,7 +3865,7 @@ impl<'a> Parser<'a> {
                                      |p| p.parse_fn_block_arg());
 
         let output = if self.eat(&token::RARROW) {
-            self.parse_ty(false)
+            self.parse_ty(true)
         } else {
             P(Ty {
                 id: ast::DUMMY_NODE_ID,
@@ -3942,7 +3977,7 @@ impl<'a> Parser<'a> {
         let could_be_trait = self.token != token::LPAREN;
 
         // Parse the trait.
-        let mut ty = self.parse_ty(false);
+        let mut ty = self.parse_ty(true);
 
         // Parse traits, if necessary.
         let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
@@ -3965,7 +4000,7 @@ impl<'a> Parser<'a> {
                 }
             };
 
-            ty = self.parse_ty(false);
+            ty = self.parse_ty(true);
             opt_trait_ref
         } else {
             None
@@ -4008,7 +4043,7 @@ impl<'a> Parser<'a> {
         let generics = self.parse_generics();
 
         let super_struct = if self.eat(&token::COLON) {
-            let ty = self.parse_ty(false);
+            let ty = self.parse_ty(true);
             match ty.node {
                 TyPath(_, None, _) => {
                     Some(ty)
@@ -4051,7 +4086,7 @@ impl<'a> Parser<'a> {
                 let struct_field_ = ast::StructField_ {
                     kind: UnnamedField(p.parse_visibility()),
                     id: ast::DUMMY_NODE_ID,
-                    ty: p.parse_ty(false),
+                    ty: p.parse_ty(true),
                     attrs: attrs,
                 };
                 spanned(lo, p.span.hi, struct_field_)
@@ -4205,7 +4240,7 @@ impl<'a> Parser<'a> {
         let m = if self.eat_keyword(keywords::Mut) {MutMutable} else {MutImmutable};
         let id = self.parse_ident();
         self.expect(&token::COLON);
-        let ty = self.parse_ty(false);
+        let ty = self.parse_ty(true);
         self.expect(&token::EQ);
         let e = self.parse_expr();
         self.commit_expr_expecting(e, token::SEMI);
@@ -4386,7 +4421,7 @@ impl<'a> Parser<'a> {
 
         let ident = self.parse_ident();
         self.expect(&token::COLON);
-        let ty = self.parse_ty(false);
+        let ty = self.parse_ty(true);
         let hi = self.span.hi;
         self.expect(&token::SEMI);
         box(GC) ast::ForeignItem {
@@ -4514,7 +4549,7 @@ impl<'a> Parser<'a> {
         let ident = self.parse_ident();
         let tps = self.parse_generics();
         self.expect(&token::EQ);
-        let ty = self.parse_ty(false);
+        let ty = self.parse_ty(true);
         self.expect(&token::SEMI);
         (ident, ItemTy(ty, tps), None)
     }
@@ -4562,7 +4597,7 @@ impl<'a> Parser<'a> {
                     &token::LPAREN,
                     &token::RPAREN,
                     seq_sep_trailing_disallowed(token::COMMA),
-                    |p| p.parse_ty(false)
+                    |p| p.parse_ty(true)
                 );
                 for ty in arg_tys.move_iter() {
                     args.push(ast::VariantArg {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 77bc967b92d..63acdb1a6ca 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -495,6 +495,11 @@ impl<'a> State<'a> {
                 }
                 try!(self.pclose());
             }
+            ast::TyParen(ref typ) => {
+                try!(self.popen());
+                try!(self.print_type(&**typ));
+                try!(self.pclose());
+            }
             ast::TyBareFn(f) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
@@ -1673,7 +1678,7 @@ impl<'a> State<'a> {
 
         match *opt_bounds {
             None => Ok(()),
-            Some(ref bounds) => self.print_bounds(&None, bounds, true),
+            Some(ref bounds) => self.print_bounds(&None, bounds, true, true),
         }
     }
 
@@ -1932,9 +1937,16 @@ impl<'a> State<'a> {
     pub fn print_bounds(&mut self,
                         region: &Option<ast::Lifetime>,
                         bounds: &OwnedSlice<ast::TyParamBound>,
-                        print_colon_anyway: bool) -> IoResult<()> {
+                        print_colon_anyway: bool,
+                        print_plus_before_bounds: bool)
+                        -> IoResult<()> {
+        let separator = if print_plus_before_bounds {
+            "+"
+        } else {
+            ":"
+        };
         if !bounds.is_empty() || region.is_some() {
-            try!(word(&mut self.s, ":"));
+            try!(word(&mut self.s, separator));
             let mut first = true;
             match *region {
                 Some(ref lt) => {
@@ -1976,7 +1988,7 @@ impl<'a> State<'a> {
             }
             Ok(())
         } else if print_colon_anyway {
-            word(&mut self.s, ":")
+            word(&mut self.s, separator)
         } else {
             Ok(())
         }
@@ -2011,7 +2023,10 @@ impl<'a> State<'a> {
                             try!(s.word_space("type"));
                         }
                         try!(s.print_ident(param.ident));
-                        try!(s.print_bounds(&None, &param.bounds, false));
+                        try!(s.print_bounds(&None,
+                                            &param.bounds,
+                                            false,
+                                            false));
                         match param.default {
                             Some(ref default) => {
                                 try!(space(&mut s.s));
@@ -2214,7 +2229,7 @@ impl<'a> State<'a> {
         }
 
         opt_bounds.as_ref().map(|bounds| {
-            self.print_bounds(opt_region, bounds, true)
+            self.print_bounds(opt_region, bounds, true, false)
         });
 
         try!(self.maybe_print_comment(decl.output.span.lo));
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 59771a57dfa..6f0fc217533 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -336,7 +336,7 @@ pub fn skip_ty<E, V: Visitor<E>>(_: &mut V, _: &Ty, _: E) {
 
 pub fn walk_ty<E: Clone, V: Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
     match typ.node {
-        TyUniq(ty) | TyVec(ty) | TyBox(ty) => {
+        TyUniq(ty) | TyVec(ty) | TyBox(ty) | TyParen(ty) => {
             visitor.visit_ty(&*ty, env)
         }
         TyPtr(ref mutable_type) => {
diff --git a/src/test/auxiliary/plugin_crate_outlive_expansion_phase.rs b/src/test/auxiliary/plugin_crate_outlive_expansion_phase.rs
index 213fdd6b74a..1592ffb6c67 100644
--- a/src/test/auxiliary/plugin_crate_outlive_expansion_phase.rs
+++ b/src/test/auxiliary/plugin_crate_outlive_expansion_phase.rs
@@ -27,7 +27,7 @@ impl Drop for Foo {
 
 #[plugin_registrar]
 pub fn registrar(_: &mut Registry) {
-    local_data_key!(foo: Box<Any:Send>);
-    foo.replace(Some(box Foo { foo: 10 } as Box<Any:Send>));
+    local_data_key!(foo: Box<Any+Send>);
+    foo.replace(Some(box Foo { foo: 10 } as Box<Any+Send>));
 }
 
diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs
index 1bc4e076553..3028db00f58 100644
--- a/src/test/compile-fail/issue-7013.rs
+++ b/src/test/compile-fail/issue-7013.rs
@@ -31,7 +31,7 @@ struct A {
 }
 
 fn main() {
-    let a = A {v: box B{v: None} as Box<Foo:Send>};
+    let a = A {v: box B{v: None} as Box<Foo+Send>};
     //~^ ERROR cannot pack type `~B`, which does not fulfill `Send`
     let v = Rc::new(RefCell::new(a));
     let w = v.clone();
diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs
index 5404b32eb24..651ea6abf08 100644
--- a/src/test/compile-fail/kindck-copy.rs
+++ b/src/test/compile-fail/kindck-copy.rs
@@ -45,15 +45,15 @@ fn test<'a,T,U:Copy>(_: &'a int) {
 
     // borrowed object types are generally ok
     assert_copy::<&'a Dummy>();
-    assert_copy::<&'a Dummy:Copy>();
-    assert_copy::<&'static Dummy:Copy>();
+    assert_copy::<&'a Dummy+Copy>();
+    assert_copy::<&'static Dummy+Copy>();
 
     // owned object types are not ok
     assert_copy::<Box<Dummy>>(); //~ ERROR does not fulfill
-    assert_copy::<Box<Dummy:Copy>>(); //~ ERROR does not fulfill
+    assert_copy::<Box<Dummy+Copy>>(); //~ ERROR does not fulfill
 
     // mutable object types are not ok
-    assert_copy::<&'a mut Dummy:Copy>();  //~ ERROR does not fulfill
+    assert_copy::<&'a mut Dummy+Copy>();  //~ ERROR does not fulfill
 
     // closures are like an `&mut` object
     assert_copy::<||>(); //~ ERROR does not fulfill
diff --git a/src/test/compile-fail/kindck-send.rs b/src/test/compile-fail/kindck-send.rs
index aa9d2dda22a..0414e64f1b7 100644
--- a/src/test/compile-fail/kindck-send.rs
+++ b/src/test/compile-fail/kindck-send.rs
@@ -39,17 +39,17 @@ fn test<'a,T,U:Send>(_: &'a int) {
     // careful with object types, who knows what they close over...
     assert_send::<&'static Dummy>(); //~ ERROR does not fulfill `Send`
     assert_send::<&'a Dummy>(); //~ ERROR does not fulfill `Send`
-    assert_send::<&'a Dummy:Send>(); //~ ERROR does not fulfill `Send`
-    assert_send::<Box<Dummy:>>(); //~ ERROR does not fulfill `Send`
+    assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill `Send`
+    assert_send::<Box<Dummy+>>(); //~ ERROR does not fulfill `Send`
 
     // ...unless they are properly bounded
-    assert_send::<&'static Dummy:Send>();
-    assert_send::<Box<Dummy:Send>>();
+    assert_send::<&'static Dummy+Send>();
+    assert_send::<Box<Dummy+Send>>();
 
     // but closure and object types can have lifetime bounds which make
     // them not ok (FIXME #5121)
     // assert_send::<proc:'a()>(); // ERROR does not fulfill `Send`
-    // assert_send::<Box<Dummy:'a>>(); // ERROR does not fulfill `Send`
+    // assert_send::<Box<Dummy+'a>>(); // ERROR does not fulfill `Send`
 
     // unsafe ptrs are ok unless they point at unsendable things
     assert_send::<*int>();
diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs
index 12205ef062d..3737025da6c 100644
--- a/src/test/compile-fail/trait-bounds-cant-coerce.rs
+++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs
@@ -12,14 +12,14 @@
 trait Foo {
 }
 
-fn a(_x: Box<Foo:Send>) {
+fn a(_x: Box<Foo+Send>) {
 }
 
-fn c(x: Box<Foo:Share+Send>) {
+fn c(x: Box<Foo+Share+Send>) {
     a(x);
 }
 
-fn d(x: Box<Foo:>) {
+fn d(x: Box<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
index 9447030a7f4..d548098ebe1 100644
--- a/src/test/compile-fail/trait-bounds-sugar.rs
+++ b/src/test/compile-fail/trait-bounds-sugar.rs
@@ -13,17 +13,17 @@
 
 trait Foo {}
 
-fn a(_x: Box<Foo:Send>) {
+fn a(_x: Box<Foo+Send>) {
 }
 
-fn b(_x: &'static Foo) { // should be same as &'static Foo:'static
+fn b(_x: &'static Foo) { // should be same as &'static Foo+'static
 }
 
-fn c(x: Box<Foo:Share>) {
+fn c(x: Box<Foo+Share>) {
     a(x); //~ ERROR expected bounds `Send`
 }
 
-fn d(x: &'static Foo:Share) {
+fn d(x: &'static Foo+Share) {
     b(x); //~ ERROR expected bounds `'static`
 }
 
diff --git a/src/test/run-fail/fail-macro-any.rs b/src/test/run-fail/fail-macro-any.rs
index 09b50743308..c56eabbb3b4 100644
--- a/src/test/run-fail/fail-macro-any.rs
+++ b/src/test/run-fail/fail-macro-any.rs
@@ -12,5 +12,5 @@
 
 
 fn main() {
-    fail!(box 413 as Box<::std::any::Any:Send>);
+    fail!(box 413 as Box<::std::any::Any+Send>);
 }
diff --git a/src/test/run-pass/alignment-gep-tup-like-1.rs b/src/test/run-pass/alignment-gep-tup-like-1.rs
index 38a3d3c5fff..4fa695de522 100644
--- a/src/test/run-pass/alignment-gep-tup-like-1.rs
+++ b/src/test/run-pass/alignment-gep-tup-like-1.rs
@@ -33,7 +33,7 @@ fn f<A:Clone + 'static>(a: A, b: u16) -> Box<Invokable<A>:> {
     box Invoker {
         a: a,
         b: b,
-    } as Box<Invokable<A>>:
+    } as (Box<Invokable<A>>+)
 }
 
 pub fn main() {
diff --git a/src/test/run-pass/as-precedence.rs b/src/test/run-pass/as-precedence.rs
new file mode 100644
index 00000000000..0760f13200c
--- /dev/null
+++ b/src/test/run-pass/as-precedence.rs
@@ -0,0 +1,18 @@
+// Copyright 2012 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 main() {
+    assert_eq!(3 as uint * 3, 9);
+    assert_eq!(3 as (uint) * 3, 9);
+    assert_eq!(3 as (uint) / 3, 1);
+    assert_eq!(3 as uint + 3, 6);
+    assert_eq!(3 as (uint) + 3, 6);
+}
+
diff --git a/src/test/run-pass/capturing-logging.rs b/src/test/run-pass/capturing-logging.rs
index 3402db7c355..23607e16795 100644
--- a/src/test/run-pass/capturing-logging.rs
+++ b/src/test/run-pass/capturing-logging.rs
@@ -41,7 +41,7 @@ fn main() {
     let (tx, rx) = channel();
     let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
     spawn(proc() {
-        set_logger(box MyWriter(w) as Box<Logger:Send>);
+        set_logger(box MyWriter(w) as Box<Logger+Send>);
         debug!("debug");
         info!("info");
     });
diff --git a/src/test/run-pass/close-over-big-then-small-data.rs b/src/test/run-pass/close-over-big-then-small-data.rs
index acae6135937..3d642be082c 100644
--- a/src/test/run-pass/close-over-big-then-small-data.rs
+++ b/src/test/run-pass/close-over-big-then-small-data.rs
@@ -33,11 +33,11 @@ impl<A:Clone> Invokable<A> for Invoker<A> {
     }
 }
 
-fn f<A:Clone + 'static>(a: A, b: u16) -> Box<Invokable<A>:> {
+fn f<A:Clone + 'static>(a: A, b: u16) -> Box<Invokable<A>+> {
     box Invoker {
         a: a,
         b: b,
-    } as Box<Invokable<A>>:
+    } as (Box<Invokable<A>>+)
 }
 
 pub fn main() {
diff --git a/src/test/run-pass/trait-bounds-basic.rs b/src/test/run-pass/trait-bounds-basic.rs
index 68ebf2c6382..d1bb0db511b 100644
--- a/src/test/run-pass/trait-bounds-basic.rs
+++ b/src/test/run-pass/trait-bounds-basic.rs
@@ -12,21 +12,21 @@
 trait Foo {
 }
 
-fn a(_x: Box<Foo:>) {
+fn a(_x: Box<Foo+>) {
 }
 
-fn b(_x: Box<Foo:Send>) {
+fn b(_x: Box<Foo+Send>) {
 }
 
-fn c(x: Box<Foo:Share+Send>) {
+fn c(x: Box<Foo+Share+Send>) {
     a(x);
 }
 
-fn d(x: Box<Foo:Send>) {
+fn d(x: Box<Foo+Send>) {
     b(x);
 }
 
-fn e(x: Box<Foo>) { // sugar for Box<Foo:Owned>
+fn e(x: Box<Foo>) { // sugar for Box<Foo+Owned>
     a(x);
 }
 
diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs
index 4ca67811982..18a0e5d471c 100644
--- a/src/test/run-pass/trait-bounds-in-arc.rs
+++ b/src/test/run-pass/trait-bounds-in-arc.rs
@@ -71,10 +71,10 @@ pub fn main() {
         swim_speed: 998,
         name: "alec_guinness".to_string(),
     };
-    let arc = Arc::new(vec!(box catte  as Box<Pet:Share+Send>,
-                            box dogge1 as Box<Pet:Share+Send>,
-                            box fishe  as Box<Pet:Share+Send>,
-                            box dogge2 as Box<Pet:Share+Send>));
+    let arc = Arc::new(vec!(box catte  as Box<Pet+Share+Send>,
+                            box dogge1 as Box<Pet+Share+Send>,
+                            box fishe  as Box<Pet+Share+Send>,
+                            box dogge2 as Box<Pet+Share+Send>));
     let (tx1, rx1) = channel();
     let arc1 = arc.clone();
     task::spawn(proc() { check_legs(arc1); tx1.send(()); });
@@ -89,21 +89,21 @@ pub fn main() {
     rx3.recv();
 }
 
-fn check_legs(arc: Arc<Vec<Box<Pet:Share+Send>>>) {
+fn check_legs(arc: Arc<Vec<Box<Pet+Share+Send>>>) {
     let mut legs = 0;
     for pet in arc.iter() {
         legs += pet.num_legs();
     }
     assert!(legs == 12);
 }
-fn check_names(arc: Arc<Vec<Box<Pet:Share+Send>>>) {
+fn check_names(arc: Arc<Vec<Box<Pet+Share+Send>>>) {
     for pet in arc.iter() {
         pet.name(|name| {
             assert!(name[0] == 'a' as u8 && name[1] == 'l' as u8);
         })
     }
 }
-fn check_pedigree(arc: Arc<Vec<Box<Pet:Share+Send>>>) {
+fn check_pedigree(arc: Arc<Vec<Box<Pet+Share+Send>>>) {
     for pet in arc.iter() {
         assert!(pet.of_good_pedigree());
     }
diff --git a/src/test/run-pass/trait-cast.rs b/src/test/run-pass/trait-cast.rs
index a9067ef87ba..0f99998b7a6 100644
--- a/src/test/run-pass/trait-cast.rs
+++ b/src/test/run-pass/trait-cast.rs
@@ -20,7 +20,7 @@ struct Tree(@RefCell<TreeR>);
 struct TreeR {
     left: Option<Tree>,
     right: Option<Tree>,
-    val: Box<to_str:Send>
+    val: Box<to_str+Send>
 }
 
 trait to_str {
@@ -57,10 +57,10 @@ fn foo<T:to_str>(x: T) -> String { x.to_str_() }
 pub fn main() {
     let t1 = Tree(@RefCell::new(TreeR{left: None,
                                       right: None,
-                                      val: box 1 as Box<to_str:Send>}));
+                                      val: box 1 as Box<to_str+Send>}));
     let t2 = Tree(@RefCell::new(TreeR{left: Some(t1),
                                       right: Some(t1),
-                                      val: box 2 as Box<to_str:Send>}));
+                                      val: box 2 as Box<to_str+Send>}));
     let expected =
         "[2, some([1, none, none]), some([1, none, none])]".to_string();
     assert!(t2.to_str_() == expected);
diff --git a/src/test/run-pass/trait-contravariant-self.rs b/src/test/run-pass/trait-contravariant-self.rs
index 1576c646286..d8df5d5600c 100644
--- a/src/test/run-pass/trait-contravariant-self.rs
+++ b/src/test/run-pass/trait-contravariant-self.rs
@@ -10,8 +10,8 @@
 
 // This is an interesting test case. We have a trait (Bar) that is
 // implemented for a `Box<Foo>` object (note: no bounds). And then we
-// have a `Box<Foo:Send>` object. The impl for `Box<Foo>` is applicable
-// to `Box<Foo:Send>` because:
+// have a `Box<Foo+Send>` object. The impl for `Box<Foo>` is applicable
+// to `Box<Foo+Send>` because:
 //
 // 1. The trait Bar is contravariant w/r/t Self because `Self` appears
 //    only in argument position.
@@ -30,7 +30,7 @@ impl Bar for Box<Foo> { fn dummy(&self) { } }
 fn wants_bar<B:Bar>(b: &B) { }
 
 fn main() {
-    let x: Box<Foo:Send> = (box SFoo);
+    let x: Box<Foo+Send> = (box SFoo);
     wants_bar(&x);
 }