]> git.lizzy.rs Git - rust.git/commitdiff
Implement the new parsing rules for types in the parser, modifying the AST appropriately.
authorNiko Matsakis <niko@alum.mit.edu>
Thu, 20 Nov 2014 20:05:29 +0000 (15:05 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 26 Nov 2014 16:42:05 +0000 (11:42 -0500)
src/librustc/diagnostics.rs
src/librustc/middle/resolve.rs
src/librustc/middle/typeck/astconv.rs
src/libsyntax/ast.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs

index afbb18faa0b9f0dd170a55f6fa5b2a669fcde235..1873213fadf1da05fdbb28fe3038e17d60463280 100644 (file)
     E0166,
     E0167,
     E0168,
-    E0169
+    E0169,
+    E0170,
+    E0171
 )
index 68a31c83ea4842dd3d65cbf760bdf9a1677df519..d334395e9117f2c54c027fa920c566288d1f8454 100644 (file)
@@ -1396,29 +1396,53 @@ fn build_reduced_graph_for_item(&mut self,
                 // methods within to a new module, if the type was defined
                 // within this module.
 
-                // Create the module and add all methods.
-                match ty.node {
-                    TyPath(ref path, _, _) if path.segments.len() == 1 => {
+                let mod_name = match ty.node {
+                    TyPath(ref path, _) if path.segments.len() == 1 => {
                         // FIXME(18446) we should distinguish between the name of
                         // a trait and the name of an impl of that trait.
-                        let mod_name = path.segments.last().unwrap().identifier.name;
+                        Some(path.segments.last().unwrap().identifier.name)
+                    }
+                    TyObjectSum(ref lhs_ty, _) => {
+                        match lhs_ty.node {
+                            TyPath(ref path, _) if path.segments.len() == 1 => {
+                                Some(path.segments.last().unwrap().identifier.name)
+                            }
+                            _ => {
+                                None
+                            }
+                        }
+                    }
+                    _ => {
+                        None
+                    }
+                };
 
+                match mod_name {
+                    None => {
+                        self.resolve_error(ty.span,
+                                           "inherent implementations may \
+                                            only be implemented in the same \
+                                            module as the type they are \
+                                            implemented for")
+                    }
+                    Some(mod_name) => {
+                        // Create the module and add all methods.
                         let parent_opt = parent.module().children.borrow()
-                                               .get(&mod_name).cloned();
+                            .get(&mod_name).cloned();
                         let new_parent = match parent_opt {
                             // It already exists
                             Some(ref child) if child.get_module_if_available()
-                                                .is_some() &&
-                                           (child.get_module().kind.get() == ImplModuleKind ||
-                                            child.get_module().kind.get() == TraitModuleKind) => {
-                                ModuleReducedGraphParent(child.get_module())
-                            }
+                                .is_some() &&
+                                (child.get_module().kind.get() == ImplModuleKind ||
+                                 child.get_module().kind.get() == TraitModuleKind) => {
+                                    ModuleReducedGraphParent(child.get_module())
+                                }
                             Some(ref child) if child.get_module_if_available()
-                                                .is_some() &&
-                                           child.get_module().kind.get() ==
-                                                EnumModuleKind => {
-                                ModuleReducedGraphParent(child.get_module())
-                            }
+                                .is_some() &&
+                                child.get_module().kind.get() ==
+                                EnumModuleKind => {
+                                    ModuleReducedGraphParent(child.get_module())
+                                }
                             // Create the module
                             _ => {
                                 let name_bindings =
@@ -1433,7 +1457,7 @@ fn build_reduced_graph_for_item(&mut self,
                                 let ns = TypeNS;
                                 let is_public =
                                     !name_bindings.defined_in_namespace(ns) ||
-                                     name_bindings.defined_in_public_namespace(ns);
+                                    name_bindings.defined_in_public_namespace(ns);
 
                                 name_bindings.define_module(parent_link,
                                                             Some(def_id),
@@ -1459,21 +1483,21 @@ fn build_reduced_graph_for_item(&mut self,
                                                        ForbidDuplicateValues,
                                                        method.span);
                                     let def = match method.pe_explicit_self()
-                                                          .node {
-                                        SelfStatic => {
-                                            // Static methods become
-                                            // `DefStaticMethod`s.
-                                            DefStaticMethod(local_def(method.id),
-                                                            FromImpl(local_def(item.id)))
-                                        }
-                                        _ => {
-                                            // Non-static methods become
-                                            // `DefMethod`s.
-                                            DefMethod(local_def(method.id),
-                                                      None,
-                                                      FromImpl(local_def(item.id)))
-                                        }
-                                    };
+                                        .node {
+                                            SelfStatic => {
+                                                // Static methods become
+                                                // `DefStaticMethod`s.
+                                                DefStaticMethod(local_def(method.id),
+                                                                FromImpl(local_def(item.id)))
+                                            }
+                                            _ => {
+                                                // Non-static methods become
+                                                // `DefMethod`s.
+                                                DefMethod(local_def(method.id),
+                                                          None,
+                                                          FromImpl(local_def(item.id)))
+                                            }
+                                        };
 
                                     // NB: not IMPORTABLE
                                     let modifiers = if method.pe_vis() == ast::Public {
@@ -1496,7 +1520,7 @@ fn build_reduced_graph_for_item(&mut self,
                                             ForbidDuplicateTypesAndModules,
                                             typedef.span);
                                     let def = DefAssociatedTy(local_def(
-                                            typedef.id));
+                                        typedef.id));
                                     // NB: not IMPORTABLE
                                     let modifiers = if typedef.vis == ast::Public {
                                         PUBLIC
@@ -1511,13 +1535,6 @@ fn build_reduced_graph_for_item(&mut self,
                             }
                         }
                     }
-                    _ => {
-                        self.resolve_error(ty.span,
-                                           "inherent implementations may \
-                                            only be implemented in the same \
-                                            module as the type they are \
-                                            implemented for")
-                    }
                 }
 
                 parent
index fd5b1bd4793b5094b0694e5fa0e0cc929e7ef33d..8f1e2d115d3f139f831d71c920262afc7996dc0e 100644 (file)
@@ -59,8 +59,9 @@
                              ShiftedRscope, BindingRscope};
 use middle::typeck::rscope;
 use middle::typeck::TypeAndSubsts;
+use util::common::ErrorReported;
 use util::nodemap::DefIdMap;
-use util::ppaux::{Repr, UserString};
+use util::ppaux::{mod, Repr, UserString};
 
 use std::rc::Rc;
 use std::iter::AdditiveIterator;
@@ -585,7 +586,7 @@ fn check_path_args(tcx: &ty::ctxt,
 pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
                                -> Option<Ty<'tcx>> {
     match ast_ty.node {
-        ast::TyPath(ref path, _, id) => {
+        ast::TyPath(ref path, id) => {
             let a_def = match tcx.def_map.borrow().get(&id) {
                 None => {
                     tcx.sess.span_bug(ast_ty.span,
@@ -642,7 +643,7 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
     }
 
     match ast_ty.node {
-        ast::TyPath(ref path, _, id) => {
+        ast::TyPath(ref path, id) => {
             let a_def = match this.tcx().def_map.borrow().get(&id) {
                 None => {
                     this.tcx()
@@ -682,64 +683,92 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
     }
 }
 
-// Handle `~`, `Box`, and `&` being able to mean strs and vecs.
-// If a_seq_ty is a str or a vec, make it a str/vec.
-// Also handle first-class trait types.
-fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
-        this: &AC,
-        rscope: &RS,
-        a_seq_mutbl: ast::Mutability,
-        a_seq_ty: &ast::Ty,
-        region: ty::Region,
-        constr: |Ty<'tcx>| -> Ty<'tcx>)
-        -> Ty<'tcx>
+fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC,
+                                   rscope: &RS,
+                                   ty: &ast::Ty,
+                                   bounds: &[ast::TyParamBound])
+                                   -> Result<ty::TraitRef<'tcx>, ErrorReported>
+    where AC : AstConv<'tcx>, RS : RegionScope
 {
-    let tcx = this.tcx();
-
-    debug!("mk_pointer(region={}, a_seq_ty={})",
-           region,
-           a_seq_ty.repr(tcx));
+    /*!
+     * In a type like `Foo + Send`, we want to wait to collect the
+     * full set of bounds before we make the object type, because we
+     * need them to infer a region bound.  (For example, if we tried
+     * made a type from just `Foo`, then it wouldn't be enough to
+     * infer a 'static bound, and hence the user would get an error.)
+     * So this function is used when we're dealing with a sum type to
+     * convert the LHS. It only accepts a type that refers to a trait
+     * name, and reports an error otherwise.
+     */
 
-    match a_seq_ty.node {
-        ast::TyVec(ref ty) => {
-            let ty = ast_ty_to_ty(this, rscope, &**ty);
-            return constr(ty::mk_vec(tcx, ty, None));
+    match ty.node {
+        ast::TyPath(ref path, id) => {
+            match this.tcx().def_map.borrow().get(&id) {
+                Some(&def::DefTrait(trait_def_id)) => {
+                    return Ok(ast_path_to_trait_ref(this,
+                                                    rscope,
+                                                    trait_def_id,
+                                                    None,
+                                                    path));
+                }
+                _ => {
+                    span_err!(this.tcx().sess, ty.span, E0170, "expected a reference to a trait");
+                    Err(ErrorReported)
+                }
+            }
         }
-        ast::TyPath(ref path, ref opt_bounds, id) => {
-            // Note that the "bounds must be empty if path is not a trait"
-            // restriction is enforced in the below case for ty_path, which
-            // will run after this as long as the path isn't a trait.
-            match tcx.def_map.borrow().get(&id) {
-                Some(&def::DefPrimTy(ast::TyStr)) => {
-                    check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                    return ty::mk_str_slice(tcx, region, a_seq_mutbl);
+        _ => {
+            span_err!(this.tcx().sess, ty.span, E0171,
+                      "expected a path on the left-hand side of `+`, not `{}`",
+                      pprust::ty_to_string(ty));
+            match ty.node {
+                ast::TyRptr(None, ref mut_ty) => {
+                    span_note!(this.tcx().sess, ty.span,
+                               "perhaps you meant `&{}({} +{})`? (per RFC 248)",
+                               ppaux::mutability_to_string(mut_ty.mutbl),
+                               pprust::ty_to_string(&*mut_ty.ty),
+                               pprust::bounds_to_string(bounds));
                 }
-                Some(&def::DefTrait(trait_def_id)) => {
-                    let result = ast_path_to_trait_ref(this,
-                                                       rscope,
-                                                       trait_def_id,
-                                                       None,
-                                                       path);
-                    let empty_vec = [];
-                    let bounds = match *opt_bounds { None => empty_vec.as_slice(),
-                                                     Some(ref bounds) => bounds.as_slice() };
-                    let existential_bounds = conv_existential_bounds(this,
-                                                                     rscope,
-                                                                     path.span,
-                                                                     &[Rc::new(result.clone())],
-                                                                     bounds);
-                    let tr = ty::mk_trait(tcx,
-                                          result,
-                                          existential_bounds);
-                    return ty::mk_rptr(tcx, region, ty::mt{mutbl: a_seq_mutbl, ty: tr});
+
+                ast::TyRptr(Some(ref lt), ref mut_ty) => {
+                    span_note!(this.tcx().sess, ty.span,
+                               "perhaps you meant `&{} {}({} +{})`? (per RFC 248)",
+                               pprust::lifetime_to_string(lt),
+                               ppaux::mutability_to_string(mut_ty.mutbl),
+                               pprust::ty_to_string(&*mut_ty.ty),
+                               pprust::bounds_to_string(bounds));
+                }
+
+                _ => {
+                    span_note!(this.tcx().sess, ty.span,
+                               "perhaps you forget parentheses? (per RFC 248)");
                 }
-                _ => {}
             }
+            Err(ErrorReported)
         }
-        _ => {}
     }
 
-    constr(ast_ty_to_ty(this, rscope, a_seq_ty))
+}
+
+fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
+                                        rscope: &RS,
+                                        span: Span,
+                                        trait_ref: ty::TraitRef<'tcx>,
+                                        bounds: &[ast::TyParamBound])
+                                        -> Ty<'tcx>
+    where AC : AstConv<'tcx>, RS : RegionScope
+{
+    let existential_bounds = conv_existential_bounds(this,
+                                                     rscope,
+                                                     span,
+                                                     &[Rc::new(trait_ref.clone())],
+                                                     bounds);
+
+    let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds);
+    debug!("trait_ref_to_object_type: result={}",
+           result.repr(this.tcx()));
+
+    result
 }
 
 fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
@@ -806,6 +835,17 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
             ast::TyVec(ref ty) => {
                 ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
             }
+            ast::TyObjectSum(ref ty, ref bounds) => {
+                match ast_ty_to_trait_ref(this, rscope, &**ty, bounds.as_slice()) {
+                    Ok(trait_ref) => {
+                        trait_ref_to_object_type(this, rscope, ast_ty.span,
+                                                 trait_ref, bounds.as_slice())
+                    }
+                    Err(ErrorReported) => {
+                        ty::mk_err()
+                    }
+                }
+            }
             ast::TyPtr(ref mt) => {
                 ty::mk_ptr(tcx, ty::mt {
                     ty: ast_ty_to_ty(this, rscope, &*mt.ty),
@@ -815,8 +855,8 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
             ast::TyRptr(ref region, ref mt) => {
                 let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
                 debug!("ty_rptr r={}", r.repr(this.tcx()));
-                mk_pointer(this, rscope, mt.mutbl, &*mt.ty, r,
-                           |ty| ty::mk_rptr(tcx, r, ty::mt {ty: ty, mutbl: mt.mutbl}))
+                let t = ast_ty_to_ty(this, rscope, &*mt.ty);
+                ty::mk_rptr(tcx, r, ty::mt {ty: t, mutbl: mt.mutbl})
             }
             ast::TyTup(ref fields) => {
                 let flds = fields.iter()
@@ -874,7 +914,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
             ast::TyPolyTraitRef(ref bounds) => {
                 conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds.as_slice())
             }
-            ast::TyPath(ref path, ref bounds, id) => {
+            ast::TyPath(ref path, id) => {
                 let a_def = match tcx.def_map.borrow().get(&id) {
                     None => {
                         tcx.sess
@@ -884,35 +924,16 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                     }
                     Some(&d) => d
                 };
-                // Kind bounds on path types are only supported for traits.
-                match a_def {
-                    // But don't emit the error if the user meant to do a trait anyway.
-                    def::DefTrait(..) => { },
-                    _ if bounds.is_some() =>
-                        tcx.sess.span_err(ast_ty.span,
-                                          "kind bounds can only be used on trait types"),
-                    _ => { },
-                }
                 match a_def {
                     def::DefTrait(trait_def_id) => {
+                        // N.B. this case overlaps somewhat with
+                        // TyObjectSum, see that fn for details
                         let result = ast_path_to_trait_ref(this,
                                                            rscope,
                                                            trait_def_id,
                                                            None,
                                                            path);
-                        let empty_bounds: &[ast::TyParamBound] = &[];
-                        let ast_bounds = match *bounds {
-                            Some(ref b) => b.as_slice(),
-                            None => empty_bounds
-                        };
-                        let bounds = conv_existential_bounds(this,
-                                                             rscope,
-                                                             ast_ty.span,
-                                                             &[Rc::new(result.clone())],
-                                                             ast_bounds);
-                        let result_ty = ty::mk_trait(tcx, result, bounds);
-                        debug!("ast_ty_to_ty: result_ty={}", result_ty.repr(this.tcx()));
-                        result_ty
+                        trait_ref_to_object_type(this, rscope, path.span, result, &[])
                     }
                     def::DefTy(did, _) | def::DefStruct(did) => {
                         ast_path_to_ty(this, rscope, did, path).ty
index 3d33774aa55e1d922f5dde98082affd89dc9ef3a..14f164ff23b825143ceb9cedb2aa057be4b389d7 100644 (file)
@@ -1151,7 +1151,9 @@ pub enum Ty_ {
     /// A path (`module::module::...::Type`) or primitive
     ///
     /// Type parameters are stored in the Path itself
-    TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above
+    TyPath(Path, NodeId),
+    /// Something like `A+B`. Note that `B` must always be a path.
+    TyObjectSum(P<Ty>, TyParamBounds),
     /// A type like `for<'a> Foo<&'a Bar>`
     TyPolyTraitRef(TyParamBounds),
     /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
index 96659031e6a37db4aa2c7bbfd424d1d84df8c124..b46f7cdfe22ad1b43e3d9d6633781eca3db6cf4a 100644 (file)
@@ -1029,7 +1029,7 @@ fn parser_done(p: Parser){
                                                 parameters: ast::PathParameters::none(),
                                             }
                                         ),
-                                        }, None, ast::DUMMY_NODE_ID),
+                                        }, ast::DUMMY_NODE_ID),
                                         span:sp(10,13)
                                     }),
                                     pat: P(ast::Pat {
index c731a0005f8843228efff3f7ecf7942932baa771..35187ebb5221065a5e0482ae59ae0f8b599cdb4f 100644 (file)
@@ -111,16 +111,6 @@ pub enum PathParsingMode {
     /// A path with a lifetime and type parameters with double colons before
     /// 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
-    /// form does not use extra double colons.
-    LifetimeAndTypesAndBounds,
-}
-
-/// A path paired with optional type bounds.
-pub struct PathAndBounds {
-    pub path: ast::Path,
-    pub bounds: Option<ast::TyParamBounds>,
 }
 
 enum ItemOrViewItem {
@@ -1053,17 +1043,9 @@ pub fn parse_for_in_type(&mut self) -> Ty_ {
         }
     }
 
-    pub fn parse_ty_path(&mut self, plus_allowed: bool) -> Ty_ {
-        let mode = if plus_allowed {
-            LifetimeAndTypesAndBounds
-        } else {
-            LifetimeAndTypesWithoutColons
-        };
-        let PathAndBounds {
-            path,
-            bounds
-        } = self.parse_path(mode);
-        TyPath(path, bounds, ast::DUMMY_NODE_ID)
+    pub fn parse_ty_path(&mut self) -> Ty_ {
+        let path = self.parse_path(LifetimeAndTypesWithoutColons);
+        TyPath(path, ast::DUMMY_NODE_ID)
     }
 
     /// parse a TyBareFn type:
@@ -1286,7 +1268,7 @@ fn parse_typedef(&mut self, attrs: Vec<Attribute>, vis: Visibility)
         let lo = self.span.lo;
         let ident = self.parse_ident();
         self.expect(&token::Eq);
-        let typ = self.parse_ty(true);
+        let typ = self.parse_ty_sum();
         let hi = self.span.hi;
         self.expect(&token::Semi);
         Typedef {
@@ -1385,7 +1367,7 @@ pub fn parse_trait_items(&mut self) -> Vec<TraitItem> {
     /// Parse a possibly mutable type
     pub fn parse_mt(&mut self) -> MutTy {
         let mutbl = self.parse_mutability();
-        let t = self.parse_ty(true);
+        let t = self.parse_ty();
         MutTy { ty: t, mutbl: mutbl }
     }
 
@@ -1396,7 +1378,7 @@ pub fn parse_ty_field(&mut self) -> TypeField {
         let mutbl = self.parse_mutability();
         let id = self.parse_ident();
         self.expect(&token::Colon);
-        let ty = self.parse_ty(true);
+        let ty = self.parse_ty_sum();
         let hi = ty.span.hi;
         ast::TypeField {
             ident: id,
@@ -1411,7 +1393,19 @@ pub fn parse_ret_ty(&mut self) -> FunctionRetTy {
             if self.eat(&token::Not) {
                 NoReturn(self.span)
             } else {
-                Return(self.parse_ty(true))
+                let t = self.parse_ty();
+
+                // We used to allow `fn foo() -> &T + U`, but don't
+                // anymore. If we see it, report a useful error.  This
+                // only makes sense because `parse_ret_ty` is only
+                // used in fn *declarations*, not fn types or where
+                // clauses (i.e., not when parsing something like
+                // `FnMut() -> T + Send`, where the `+` is legal).
+                if self.token == token::BinOp(token::Plus) {
+                    self.warn("deprecated syntax: `()` are required, see RFC 248 for details");
+                }
+
+                Return(t)
             }
         } else {
             let pos = self.span.lo;
@@ -1423,11 +1417,36 @@ pub fn parse_ret_ty(&mut self) -> FunctionRetTy {
         }
     }
 
+    /// Parse a type in a context where `T1+T2` is allowed.
+    pub fn parse_ty_sum(&mut self) -> P<Ty> {
+        let lo = self.span.lo;
+        let lhs = self.parse_ty();
+
+        if !self.eat(&token::BinOp(token::Plus)) {
+            return lhs;
+        }
+
+        let bounds = self.parse_ty_param_bounds();
+
+        // In type grammar, `+` is treated like a binary operator,
+        // and hence both L and R side are required.
+        if bounds.len() == 0 {
+            let last_span = self.last_span;
+            self.span_err(last_span,
+                          "at least one type parameter bound \
+                          must be specified");
+        }
+
+        let sp = mk_sp(lo, self.last_span.hi);
+        let sum = ast::TyObjectSum(lhs, bounds);
+        P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp})
+    }
+
     /// 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> {
+    pub fn parse_ty(&mut self) -> P<Ty> {
         maybe_whole!(no_clone self, NtTy);
 
         let lo = self.span.lo;
@@ -1441,7 +1460,7 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
             let mut ts = vec![];
             let mut last_comma = false;
             while self.token != token::CloseDelim(token::Paren) {
-                ts.push(self.parse_ty(true));
+                ts.push(self.parse_ty_sum());
                 if self.token == token::Comma {
                     last_comma = true;
                     self.bump();
@@ -1465,7 +1484,7 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
                 token::OpenDelim(token::Bracket) => self.obsolete(last_span, ObsoleteOwnedVector),
                 _ => self.obsolete(last_span, ObsoleteOwnedType)
             }
-            TyTup(vec![self.parse_ty(false)])
+            TyTup(vec![self.parse_ty()])
         } else if self.token == token::BinOp(token::Star) {
             // STAR POINTER (bare pointer?)
             self.bump();
@@ -1473,7 +1492,7 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
         } else if self.token == token::OpenDelim(token::Bracket) {
             // VECTOR
             self.expect(&token::OpenDelim(token::Bracket));
-            let t = self.parse_ty(true);
+            let t = self.parse_ty_sum();
 
             // Parse the `, ..e` in `[ int, ..e ]`
             // where `e` is a const expression
@@ -1514,7 +1533,7 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
         } else if self.token == token::Lt {
             // QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
             self.bump();
-            let self_type = self.parse_ty(true);
+            let self_type = self.parse_ty_sum();
             self.expect_keyword(keywords::As);
             let trait_ref = self.parse_trait_ref();
             self.expect(&token::Gt);
@@ -1529,7 +1548,7 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
                   self.token.is_ident() ||
                   self.token.is_path() {
             // NAMED TYPE
-            self.parse_ty_path(plus_allowed)
+            self.parse_ty_path()
         } else if self.eat(&token::Underscore) {
             // TYPE TO BE INFERRED
             TyInfer
@@ -1563,7 +1582,7 @@ pub fn parse_ptr(&mut self) -> MutTy {
                            known as `*const T`");
             MutImmutable
         };
-        let t = self.parse_ty(true);
+        let t = self.parse_ty();
         MutTy { ty: t, mutbl: mutbl }
     }
 
@@ -1603,7 +1622,7 @@ pub fn parse_arg_general(&mut self, require_name: bool) -> Arg {
                                    special_idents::invalid)
         };
 
-        let t = self.parse_ty(true);
+        let t = self.parse_ty_sum();
 
         Arg {
             ty: t,
@@ -1621,7 +1640,7 @@ pub fn parse_arg(&mut self) -> Arg {
     pub fn parse_fn_block_arg(&mut self) -> Arg {
         let pat = self.parse_pat();
         let t = if self.eat(&token::Colon) {
-            self.parse_ty(true)
+            self.parse_ty_sum()
         } else {
             P(Ty {
                 id: ast::DUMMY_NODE_ID,
@@ -1739,7 +1758,7 @@ pub fn parse_literal_maybe_minus(&mut self) -> P<Expr> {
     /// mode. The `mode` parameter determines whether lifetimes, types, and/or
     /// bounds are permitted and whether `::` must precede type parameter
     /// groups.
-    pub fn parse_path(&mut self, mode: PathParsingMode) -> PathAndBounds {
+    pub fn parse_path(&mut self, mode: PathParsingMode) -> ast::Path {
         // Check for a whole path...
         let found = match self.token {
             token::Interpolated(token::NtPath(_)) => Some(self.bump_and_get()),
@@ -1747,10 +1766,7 @@ pub fn parse_path(&mut self, mode: PathParsingMode) -> PathAndBounds {
         };
         match found {
             Some(token::Interpolated(token::NtPath(box path))) => {
-                return PathAndBounds {
-                    path: path,
-                    bounds: None
-                }
+                return path;
             }
             _ => {}
         }
@@ -1762,8 +1778,7 @@ pub fn parse_path(&mut self, mode: PathParsingMode) -> PathAndBounds {
         // identifier followed by an optional lifetime and a set of types.
         // A bound set is a set of type parameter bounds.
         let segments = match mode {
-            LifetimeAndTypesWithoutColons |
-            LifetimeAndTypesAndBounds => {
+            LifetimeAndTypesWithoutColons => {
                 self.parse_path_segments_without_colons()
             }
             LifetimeAndTypesWithColons => {
@@ -1774,44 +1789,14 @@ pub fn parse_path(&mut self, mode: PathParsingMode) -> PathAndBounds {
             }
         };
 
-        // Next, parse a plus and bounded type parameters, if
-        // applicable. We need to remember whether the separate was
-        // present for later, because in some contexts it's a parse
-        // error.
-        let opt_bounds = {
-            if mode == LifetimeAndTypesAndBounds &&
-                self.eat(&token::BinOp(token::Plus))
-            {
-                let bounds = self.parse_ty_param_bounds();
-
-                // For some reason that I do not fully understand, we
-                // do not permit an empty list in the case where it is
-                // introduced by a `+`, but we do for `:` and other
-                // separators. -nmatsakis
-                if bounds.len() == 0 {
-                    let last_span = self.last_span;
-                    self.span_err(last_span,
-                                  "at least one type parameter bound \
-                                   must be specified");
-                }
-
-                Some(bounds)
-            } else {
-                None
-            }
-        };
-
         // Assemble the span.
         let span = mk_sp(lo, self.last_span.hi);
 
         // Assemble the result.
-        PathAndBounds {
-            path: ast::Path {
-                span: span,
-                global: is_global,
-                segments: segments,
-            },
-            bounds: opt_bounds,
+        ast::Path {
+            span: span,
+            global: is_global,
+            segments: segments,
         }
     }
 
@@ -1837,10 +1822,10 @@ pub fn parse_path_segments_without_colons(&mut self) -> Vec<ast::PathSegment> {
                 let inputs = self.parse_seq_to_end(
                     &token::CloseDelim(token::Paren),
                     seq_sep_trailing_allowed(token::Comma),
-                    |p| p.parse_ty(true));
+                    |p| p.parse_ty_sum());
 
                 let output_ty = if self.eat(&token::RArrow) {
-                    Some(self.parse_ty(true))
+                    Some(self.parse_ty())
                 } else {
                     None
                 };
@@ -2327,7 +2312,7 @@ pub fn parse_bottom_expr(&mut self) -> P<Expr> {
                         !self.token.is_keyword(keywords::True) &&
                         !self.token.is_keyword(keywords::False) {
                     let pth =
-                        self.parse_path(LifetimeAndTypesWithColons).path;
+                        self.parse_path(LifetimeAndTypesWithColons);
 
                     // `!`, as an operator, is prefix, so we know this isn't that
                     if self.token == token::Not {
@@ -2898,7 +2883,7 @@ pub fn parse_more_binops(&mut self, lhs: P<Expr>, min_prec: uint) -> P<Expr> {
             }
             None => {
                 if as_prec > min_prec && self.eat_keyword(keywords::As) {
-                    let rhs = self.parse_ty(false);
+                    let rhs = self.parse_ty();
                     let _as = self.mk_expr(lhs.span.lo,
                                            rhs.span.hi,
                                            ExprCast(lhs, rhs));
@@ -3362,8 +3347,7 @@ pub fn parse_pat(&mut self) -> P<Pat> {
                     }) {
                 self.bump();
                 let end = if self.token.is_ident() || self.token.is_path() {
-                    let path = self.parse_path(LifetimeAndTypesWithColons)
-                                   .path;
+                    let path = self.parse_path(LifetimeAndTypesWithColons);
                     let hi = self.span.hi;
                     self.mk_expr(lo, hi, ExprPath(path))
                 } else {
@@ -3433,8 +3417,7 @@ pub fn parse_pat(&mut self) -> P<Pat> {
                 }
             } else {
                 // parse an enum pat
-                let enum_path = self.parse_path(LifetimeAndTypesWithColons)
-                                    .path;
+                let enum_path = self.parse_path(LifetimeAndTypesWithColons);
                 match self.token {
                     token::OpenDelim(token::Brace) => {
                         self.bump();
@@ -3548,7 +3531,7 @@ fn parse_local(&mut self) -> P<Local> {
             span: mk_sp(lo, lo),
         });
         if self.eat(&token::Colon) {
-            ty = self.parse_ty(true);
+            ty = self.parse_ty_sum();
         }
         let init = self.parse_initializer();
         P(ast::Local {
@@ -3577,7 +3560,7 @@ fn parse_name_and_ty(&mut self, pr: Visibility,
         }
         let name = self.parse_ident();
         self.expect(&token::Colon);
-        let ty = self.parse_ty(true);
+        let ty = self.parse_ty_sum();
         spanned(lo, self.last_span.hi, ast::StructField_ {
             kind: NamedField(name, pr),
             id: ast::DUMMY_NODE_ID,
@@ -3624,7 +3607,7 @@ fn check_expected_item(p: &mut Parser, attrs: &[Attribute]) {
 
             // Potential trouble: if we allow macros with paths instead of
             // idents, we'd need to look ahead past the whole path here...
-            let pth = self.parse_path(NoTypesAllowed).path;
+            let pth = self.parse_path(NoTypesAllowed);
             self.bump();
 
             let id = match self.token {
@@ -3976,7 +3959,7 @@ fn parse_ty_param(&mut self) -> TyParam {
 
         let default = if self.token == token::Eq {
             self.bump();
-            Some(self.parse_ty(true))
+            Some(self.parse_ty_sum())
         }
         else { None };
 
@@ -4032,7 +4015,7 @@ fn parse_generic_values_after_lt(&mut self) -> (Vec<ast::Lifetime>, Vec<P<Ty>> )
             Some(token::Comma),
             |p| {
                 p.forbid_lifetime();
-                p.parse_ty(true)
+                p.parse_ty_sum()
             }
         );
         (lifetimes, result.into_vec())
@@ -4265,7 +4248,7 @@ fn maybe_parse_borrowed_explicit_self(this: &mut Parser)
                     // Determine whether this is the fully explicit form, `self:
                     // TYPE`.
                     if self.eat(&token::Colon) {
-                        SelfExplicit(self.parse_ty(false), self_ident)
+                        SelfExplicit(self.parse_ty_sum(), self_ident)
                     } else {
                         SelfValue(self_ident)
                     }
@@ -4277,7 +4260,7 @@ fn maybe_parse_borrowed_explicit_self(this: &mut Parser)
                     // Determine whether this is the fully explicit form,
                     // `self: TYPE`.
                     if self.eat(&token::Colon) {
-                        SelfExplicit(self.parse_ty(false), self_ident)
+                        SelfExplicit(self.parse_ty_sum(), self_ident)
                     } else {
                         SelfValue(self_ident)
                     }
@@ -4466,7 +4449,7 @@ pub fn parse_method(&mut self,
                 && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
                     || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
                 // method macro.
-                let pth = self.parse_path(NoTypesAllowed).path;
+                let pth = self.parse_path(NoTypesAllowed);
                 self.expect(&token::Not);
 
                 // eat a matched-delimiter token tree:
@@ -4564,30 +4547,25 @@ fn parse_item_impl(&mut self) -> ItemInfo {
         let could_be_trait = self.token != token::OpenDelim(token::Paren);
 
         // Parse the trait.
-        let mut ty = self.parse_ty(true);
+        let mut ty = self.parse_ty_sum();
 
         // Parse traits, if necessary.
         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 {
-                TyPath(ref path, None, node_id) => {
+                TyPath(ref path, node_id) => {
                     Some(TraitRef {
                         path: (*path).clone(),
                         ref_id: node_id,
                     })
                 }
-                TyPath(_, Some(_), _) => {
-                    self.span_err(ty.span,
-                                  "bounded traits are only valid in type position");
-                    None
-                }
                 _ => {
                     self.span_err(ty.span, "not a trait");
                     None
                 }
             };
 
-            ty = self.parse_ty(true);
+            ty = self.parse_ty_sum();
             opt_trait_ref
         } else {
             None
@@ -4606,7 +4584,7 @@ fn parse_item_impl(&mut self) -> ItemInfo {
     /// Parse a::B<String,int>
     fn parse_trait_ref(&mut self) -> TraitRef {
         ast::TraitRef {
-            path: self.parse_path(LifetimeAndTypesWithoutColons).path,
+            path: self.parse_path(LifetimeAndTypesWithoutColons),
             ref_id: ast::DUMMY_NODE_ID,
         }
     }
@@ -4638,7 +4616,7 @@ fn parse_item_struct(&mut self) -> ItemInfo {
         let mut generics = self.parse_generics();
 
         if self.eat(&token::Colon) {
-            let ty = self.parse_ty(true);
+            let ty = self.parse_ty_sum();
             self.span_err(ty.span, "`virtual` structs have been removed from the language");
         }
 
@@ -4673,7 +4651,7 @@ fn parse_item_struct(&mut self) -> ItemInfo {
                 let struct_field_ = ast::StructField_ {
                     kind: UnnamedField(p.parse_visibility()),
                     id: ast::DUMMY_NODE_ID,
-                    ty: p.parse_ty(true),
+                    ty: p.parse_ty_sum(),
                     attrs: attrs,
                 };
                 spanned(lo, p.span.hi, struct_field_)
@@ -4830,7 +4808,7 @@ fn parse_mod_items(&mut self,
     fn parse_item_const(&mut self, m: Option<Mutability>) -> ItemInfo {
         let id = self.parse_ident();
         self.expect(&token::Colon);
-        let ty = self.parse_ty(true);
+        let ty = self.parse_ty_sum();
         self.expect(&token::Eq);
         let e = self.parse_expr();
         self.commit_expr_expecting(&*e, token::Semi);
@@ -5023,7 +5001,7 @@ fn parse_item_foreign_static(&mut self, vis: ast::Visibility,
 
         let ident = self.parse_ident();
         self.expect(&token::Colon);
-        let ty = self.parse_ty(true);
+        let ty = self.parse_ty_sum();
         let hi = self.span.hi;
         self.expect(&token::Semi);
         P(ForeignItem {
@@ -5181,7 +5159,7 @@ fn parse_item_type(&mut self) -> ItemInfo {
         let mut tps = self.parse_generics();
         self.parse_where_clause(&mut tps);
         self.expect(&token::Eq);
-        let ty = self.parse_ty(true);
+        let ty = self.parse_ty_sum();
         self.expect(&token::Semi);
         (ident, ItemTy(ty, tps), None)
     }
@@ -5235,7 +5213,7 @@ fn parse_enum_def(&mut self, _generics: &ast::Generics) -> EnumDef {
                     &token::OpenDelim(token::Paren),
                     &token::CloseDelim(token::Paren),
                     seq_sep_trailing_allowed(token::Comma),
-                    |p| p.parse_ty(true)
+                    |p| p.parse_ty_sum()
                 );
                 for ty in arg_tys.into_iter() {
                     args.push(ast::VariantArg {
@@ -5593,7 +5571,7 @@ fn parse_macro_use_or_failure(
             // MACRO INVOCATION ITEM
 
             // item macro.
-            let pth = self.parse_path(NoTypesAllowed).path;
+            let pth = self.parse_path(NoTypesAllowed);
             self.expect(&token::Not);
 
             // a 'special' identifier (like what `macro_rules!` uses)
index 6960337c3e2c9dc5f53958f09b2cf748817992a6..78412a76bfeb8d4f008419eff6d8f44af2ffbf85 100644 (file)
@@ -293,6 +293,10 @@ pub fn ty_to_string(ty: &ast::Ty) -> String {
     $to_string(|s| s.print_type(ty))
 }
 
+pub fn bounds_to_string(bounds: &[ast::TyParamBound]) -> String {
+    $to_string(|s| s.print_bounds("", bounds))
+}
+
 pub fn pat_to_string(pat: &ast::Pat) -> String {
     $to_string(|s| s.print_pat(pat))
 }
@@ -739,11 +743,15 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> {
                                       Some(&generics),
                                       None));
             }
-            ast::TyPath(ref path, ref bounds, _) => {
-                try!(self.print_bounded_path(path, bounds));
+            ast::TyPath(ref path, _) => {
+                try!(self.print_path(path, false));
+            }
+            ast::TyObjectSum(ref ty, ref bounds) => {
+                try!(self.print_type(&**ty));
+                try!(self.print_bounds("+", bounds.as_slice()));
             }
             ast::TyPolyTraitRef(ref bounds) => {
-                try!(self.print_bounds("", bounds));
+                try!(self.print_bounds("", bounds.as_slice()));
             }
             ast::TyQPath(ref qpath) => {
                 try!(word(&mut self.s, "<"));
@@ -970,7 +978,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
                     }
                     _ => {}
                 }
-                try!(self.print_bounds(":", bounds));
+                try!(self.print_bounds(":", bounds.as_slice()));
                 try!(self.print_where_clause(generics));
                 try!(word(&mut self.s, " "));
                 try!(self.bopen());
@@ -2329,7 +2337,7 @@ pub fn print_proc_args(&mut self, decl: &ast::FnDecl) -> IoResult<()> {
 
     pub fn print_bounds(&mut self,
                         prefix: &str,
-                        bounds: &OwnedSlice<ast::TyParamBound>)
+                        bounds: &[ast::TyParamBound])
                         -> IoResult<()> {
         if !bounds.is_empty() {
             try!(word(&mut self.s, prefix));
@@ -2418,7 +2426,7 @@ pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> {
             _ => {}
         }
         try!(self.print_ident(param.ident));
-        try!(self.print_bounds(":", &param.bounds));
+        try!(self.print_bounds(":", param.bounds.as_slice()));
         match param.default {
             Some(ref default) => {
                 try!(space(&mut self.s));
@@ -2447,7 +2455,7 @@ pub fn print_where_clause(&mut self, generics: &ast::Generics)
             }
 
             try!(self.print_ident(predicate.ident));
-            try!(self.print_bounds(":", &predicate.bounds));
+            try!(self.print_bounds(":", predicate.bounds.as_slice()));
         }
 
         Ok(())
@@ -2664,7 +2672,7 @@ pub fn print_ty_fn(&mut self,
             try!(self.pclose());
         }
 
-        try!(self.print_bounds(":", bounds));
+        try!(self.print_bounds(":", bounds.as_slice()));
 
         try!(self.print_fn_output(decl));