about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2015-04-30 22:30:50 +1200
committerNick Cameron <ncameron@mozilla.com>2015-04-30 22:30:50 +1200
commitb2ddd937b20d8fc26132cb7ec665784422d92926 (patch)
treecf257df60ded1b45616d797b8feb71178cab0142 /src/libsyntax/parse/parser.rs
parentc0a42aecbc85298fb6351253c4cd1824567b7a42 (diff)
parentf0bd14f7b15b978f8bf32bb368f63faa0f26c02e (diff)
downloadrust-b2ddd937b20d8fc26132cb7ec665784422d92926.tar.gz
rust-b2ddd937b20d8fc26132cb7ec665784422d92926.zip
Merge branch 'master' into mulit-decor
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs292
1 files changed, 192 insertions, 100 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 68006a8979a..5f76c214927 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -17,8 +17,8 @@ use ast::{Public, Unsafety};
 use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
 use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block};
 use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause};
-use ast::{Crate, CrateConfig, Decl, DeclItem};
-use ast::{DeclLocal, DefaultBlock, DefaultReturn};
+use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig};
+use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn};
 use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
 use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
 use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
@@ -40,8 +40,9 @@ use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
 use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
 use ast::{MutTy, BiMul, Mutability};
 use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
-use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion};
-use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle};
+use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
+use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti};
+use ast::PatWildSingle;
 use ast::{PolyTraitRef, QSelf};
 use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
 use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
@@ -87,9 +88,9 @@ use std::slice;
 
 bitflags! {
     flags Restrictions: u8 {
-        const UNRESTRICTED                  = 0b0000,
-        const RESTRICTION_STMT_EXPR         = 0b0001,
-        const RESTRICTION_NO_STRUCT_LITERAL = 0b0010,
+        const UNRESTRICTED                  = 0,
+        const RESTRICTION_STMT_EXPR         = 1 << 0,
+        const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
     }
 }
 
@@ -109,6 +110,15 @@ pub enum PathParsingMode {
     LifetimeAndTypesWithColons,
 }
 
+/// How to parse a qualified path, whether to allow trailing parameters.
+#[derive(Copy, Clone, PartialEq)]
+pub enum QPathParsingMode {
+    /// No trailing parameters, e.g. `<T as Trait>::Item`
+    NoParameters,
+    /// Optional parameters, e.g. `<T as Trait>::item::<'a, U>`
+    MaybeParameters,
+}
+
 /// How to parse a bound, whether to allow bound modifiers such as `?`.
 #[derive(Copy, Clone, PartialEq)]
 pub enum BoundParsingMode {
@@ -329,7 +339,7 @@ impl<'a> Parser<'a> {
             buffer_start: 0,
             buffer_end: 0,
             tokens_consumed: 0,
-            restrictions: UNRESTRICTED,
+            restrictions: Restrictions::UNRESTRICTED,
             quote_depth: 0,
             obsolete_set: HashSet::new(),
             mod_path_stack: Vec::new(),
@@ -902,7 +912,9 @@ impl<'a> Parser<'a> {
     pub fn bump(&mut self) -> PResult<()> {
         self.last_span = self.span;
         // Stash token for error recovery (sometimes; clone is not necessarily cheap).
-        self.last_token = if self.token.is_ident() || self.token.is_path() {
+        self.last_token = if self.token.is_ident() ||
+                          self.token.is_path() ||
+                          self.token == token::Comma {
             Some(Box::new(self.token.clone()))
         } else {
             None
@@ -1150,7 +1162,8 @@ impl<'a> Parser<'a> {
             &token::OpenDelim(token::Brace),
             &token::CloseDelim(token::Brace),
             seq_sep_none(),
-            |p| {
+            |p| -> PResult<P<TraitItem>> {
+            maybe_whole!(no_clone p, NtTraitItem);
             let mut attrs = p.parse_outer_attributes();
             let lo = p.span.lo;
 
@@ -1158,6 +1171,20 @@ impl<'a> Parser<'a> {
                 let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
                 try!(p.expect(&token::Semi));
                 (ident, TypeTraitItem(bounds, default))
+            } else if try!(p.eat_keyword(keywords::Const)) {
+                let ident = try!(p.parse_ident());
+                try!(p.expect(&token::Colon));
+                let ty = try!(p.parse_ty_sum());
+                let default = if p.check(&token::Eq) {
+                    try!(p.bump());
+                    let expr = try!(p.parse_expr_nopanic());
+                    try!(p.commit_expr_expecting(&expr, token::Semi));
+                    Some(expr)
+                } else {
+                    try!(p.expect(&token::Semi));
+                    None
+                };
+                (ident, ConstTraitItem(ty, default))
             } else {
                 let style = try!(p.parse_unsafety());
                 let abi = if try!(p.eat_keyword(keywords::Extern)) {
@@ -1331,36 +1358,9 @@ impl<'a> Parser<'a> {
             try!(self.expect(&token::CloseDelim(token::Paren)));
             TyTypeof(e)
         } else if try!(self.eat_lt()) {
-            // QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
-            let self_type = try!(self.parse_ty_sum());
-
-            let mut path = if try!(self.eat_keyword(keywords::As) ){
-                try!(self.parse_path(LifetimeAndTypesWithoutColons))
-            } else {
-                ast::Path {
-                    span: self.span,
-                    global: false,
-                    segments: vec![]
-                }
-            };
-
-            let qself = QSelf {
-                ty: self_type,
-                position: path.segments.len()
-            };
 
-            try!(self.expect(&token::Gt));
-            try!(self.expect(&token::ModSep));
-
-            path.segments.push(ast::PathSegment {
-                identifier: try!(self.parse_ident()),
-                parameters: ast::PathParameters::none()
-            });
-
-            if path.segments.len() == 1 {
-                path.span.lo = self.last_span.lo;
-            }
-            path.span.hi = self.last_span.hi;
+            let (qself, path) =
+                 try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
 
             TyPath(Some(qself), path)
         } else if self.check(&token::ModSep) ||
@@ -1577,6 +1577,61 @@ impl<'a> Parser<'a> {
         }
     }
 
+    // QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
+    // Assumes that the leading `<` has been parsed already.
+    pub fn parse_qualified_path(&mut self, mode: QPathParsingMode)
+                                -> PResult<(QSelf, ast::Path)> {
+        let self_type = try!(self.parse_ty_sum());
+        let mut path = if try!(self.eat_keyword(keywords::As)) {
+            try!(self.parse_path(LifetimeAndTypesWithoutColons))
+        } else {
+            ast::Path {
+                span: self.span,
+                global: false,
+                segments: vec![]
+            }
+        };
+
+        let qself = QSelf {
+            ty: self_type,
+            position: path.segments.len()
+        };
+
+        try!(self.expect(&token::Gt));
+        try!(self.expect(&token::ModSep));
+
+        let item_name = try!(self.parse_ident());
+        let parameters = match mode {
+            QPathParsingMode::NoParameters => ast::PathParameters::none(),
+            QPathParsingMode::MaybeParameters => {
+                if try!(self.eat(&token::ModSep)) {
+                    try!(self.expect_lt());
+                    // Consumed `item::<`, go look for types
+                    let (lifetimes, types, bindings) =
+                        try!(self.parse_generic_values_after_lt());
+                    ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                        lifetimes: lifetimes,
+                        types: OwnedSlice::from_vec(types),
+                        bindings: OwnedSlice::from_vec(bindings),
+                    })
+                } else {
+                    ast::PathParameters::none()
+                }
+            }
+        };
+        path.segments.push(ast::PathSegment {
+            identifier: item_name,
+            parameters: parameters
+        });
+
+        if path.segments.len() == 1 {
+            path.span.lo = self.last_span.lo;
+        }
+        path.span.hi = self.last_span.hi;
+
+        Ok((qself, path))
+    }
+
     /// Parses a path and optional type parameter bounds, depending on the
     /// mode. The `mode` parameter determines whether lifetimes, types, and/or
     /// bounds are permitted and whether `::` must precede type parameter
@@ -2040,49 +2095,10 @@ impl<'a> Parser<'a> {
             }
             _ => {
                 if try!(self.eat_lt()){
-                    // QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
-                    let self_type = try!(self.parse_ty_sum());
-                    let mut path = if try!(self.eat_keyword(keywords::As) ){
-                        try!(self.parse_path(LifetimeAndTypesWithoutColons))
-                    } else {
-                        ast::Path {
-                            span: self.span,
-                            global: false,
-                            segments: vec![]
-                        }
-                    };
-                    let qself = QSelf {
-                        ty: self_type,
-                        position: path.segments.len()
-                    };
-                    try!(self.expect(&token::Gt));
-                    try!(self.expect(&token::ModSep));
 
-                    let item_name = try!(self.parse_ident());
-                    let parameters = if try!(self.eat(&token::ModSep) ){
-                        try!(self.expect_lt());
-                        // Consumed `item::<`, go look for types
-                        let (lifetimes, types, bindings) =
-                            try!(self.parse_generic_values_after_lt());
-                        ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
-                            lifetimes: lifetimes,
-                            types: OwnedSlice::from_vec(types),
-                            bindings: OwnedSlice::from_vec(bindings),
-                        })
-                    } else {
-                        ast::PathParameters::none()
-                    };
-                    path.segments.push(ast::PathSegment {
-                        identifier: item_name,
-                        parameters: parameters
-                    });
-
-                    if path.segments.len() == 1 {
-                        path.span.lo = self.last_span.lo;
-                    }
-                    path.span.hi = self.last_span.hi;
+                    let (qself, path) =
+                        try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters));
 
-                    let hi = self.span.hi;
                     return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
                 }
                 if try!(self.eat_keyword(keywords::Move) ){
@@ -2182,7 +2198,10 @@ impl<'a> Parser<'a> {
                     if self.check(&token::OpenDelim(token::Brace)) {
                         // This is a struct literal, unless we're prohibited
                         // from parsing struct literals here.
-                        if !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) {
+                        let prohibited = self.restrictions.contains(
+                            Restrictions::RESTRICTION_NO_STRUCT_LITERAL
+                        );
+                        if !prohibited {
                             // It's a struct literal.
                             try!(self.bump());
                             let mut fields = Vec::new();
@@ -2743,7 +2762,7 @@ impl<'a> Parser<'a> {
     }
 
     pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> PResult<P<Expr>> {
-        let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL;
+        let restrictions = self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL;
         let op_span = self.span;
         match self.token {
           token::Eq => {
@@ -2798,7 +2817,7 @@ impl<'a> Parser<'a> {
         if self.token.can_begin_expr() {
             // parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
             if self.token == token::OpenDelim(token::Brace) {
-                return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL);
+                return !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL);
             }
             true
         } else {
@@ -2812,7 +2831,7 @@ impl<'a> Parser<'a> {
             return self.parse_if_let_expr();
         }
         let lo = self.last_span.lo;
-        let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let thn = try!(self.parse_block());
         let mut els: Option<P<Expr>> = None;
         let mut hi = thn.span.hi;
@@ -2830,7 +2849,7 @@ impl<'a> Parser<'a> {
         try!(self.expect_keyword(keywords::Let));
         let pat = try!(self.parse_pat_nopanic());
         try!(self.expect(&token::Eq));
-        let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let thn = try!(self.parse_block());
         let (hi, els) = if try!(self.eat_keyword(keywords::Else) ){
             let expr = try!(self.parse_else_expr());
@@ -2889,7 +2908,7 @@ impl<'a> Parser<'a> {
         let lo = self.last_span.lo;
         let pat = try!(self.parse_pat_nopanic());
         try!(self.expect_keyword(keywords::In));
-        let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let loop_block = try!(self.parse_block());
         let hi = self.last_span.hi;
 
@@ -2902,7 +2921,7 @@ impl<'a> Parser<'a> {
             return self.parse_while_let_expr(opt_ident);
         }
         let lo = self.last_span.lo;
-        let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let body = try!(self.parse_block());
         let hi = body.span.hi;
         return Ok(self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident)));
@@ -2914,7 +2933,7 @@ impl<'a> Parser<'a> {
         try!(self.expect_keyword(keywords::Let));
         let pat = try!(self.parse_pat_nopanic());
         try!(self.expect(&token::Eq));
-        let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let body = try!(self.parse_block());
         let hi = body.span.hi;
         return Ok(self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident)));
@@ -2929,7 +2948,7 @@ impl<'a> Parser<'a> {
 
     fn parse_match_expr(&mut self) -> PResult<P<Expr>> {
         let lo = self.last_span.lo;
-        let discriminant = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let discriminant = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         try!(self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace)));
         let mut arms: Vec<Arm> = Vec::new();
         while self.token != token::CloseDelim(token::Brace) {
@@ -2941,6 +2960,8 @@ impl<'a> Parser<'a> {
     }
 
     pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> {
+        maybe_whole!(no_clone self, NtArm);
+
         let attrs = self.parse_outer_attributes();
         let pats = try!(self.parse_pats());
         let mut guard = None;
@@ -2948,7 +2969,7 @@ impl<'a> Parser<'a> {
             guard = Some(try!(self.parse_expr_nopanic()));
         }
         try!(self.expect(&token::FatArrow));
-        let expr = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR));
+        let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR));
 
         let require_comma =
             !classify::expr_is_simple_block(&*expr)
@@ -2970,7 +2991,7 @@ impl<'a> Parser<'a> {
 
     /// Parse an expression
     pub fn parse_expr_nopanic(&mut self) -> PResult<P<Expr>> {
-        return self.parse_expr_res(UNRESTRICTED);
+        return self.parse_expr_res(Restrictions::UNRESTRICTED);
     }
 
     /// Parse an expression, subject to the given restrictions
@@ -3153,16 +3174,25 @@ impl<'a> Parser<'a> {
     fn parse_pat_range_end(&mut self) -> PResult<P<Expr>> {
         if self.is_path_start() {
             let lo = self.span.lo;
-            let path = try!(self.parse_path(LifetimeAndTypesWithColons));
+            let (qself, path) = if try!(self.eat_lt()) {
+                // Parse a qualified path
+                let (qself, path) =
+                    try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
+                (Some(qself), path)
+            } else {
+                // Parse an unqualified path
+                (None, try!(self.parse_path(LifetimeAndTypesWithColons)))
+            };
             let hi = self.last_span.hi;
-            Ok(self.mk_expr(lo, hi, ExprPath(None, path)))
+            Ok(self.mk_expr(lo, hi, ExprPath(qself, path)))
         } else {
             self.parse_literal_maybe_minus()
         }
     }
 
     fn is_path_start(&self) -> bool {
-        (self.token == token::ModSep || self.token.is_ident() || self.token.is_path())
+        (self.token == token::Lt || self.token == token::ModSep
+            || self.token.is_ident() || self.token.is_path())
             && !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False)
     }
 
@@ -3238,25 +3268,44 @@ impl<'a> Parser<'a> {
                         pat = try!(self.parse_pat_ident(BindByValue(MutImmutable)));
                     }
                 } else {
-                    // Parse as a general path
-                    let path = try!(self.parse_path(LifetimeAndTypesWithColons));
+                    let (qself, path) = if try!(self.eat_lt()) {
+                        // Parse a qualified path
+                        let (qself, path) =
+                            try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
+                        (Some(qself), path)
+                    } else {
+                        // Parse an unqualified path
+                        (None, try!(self.parse_path(LifetimeAndTypesWithColons)))
+                    };
                     match self.token {
                       token::DotDotDot => {
                         // Parse range
                         let hi = self.last_span.hi;
-                        let begin = self.mk_expr(lo, hi, ExprPath(None, path));
+                        let begin = self.mk_expr(lo, hi, ExprPath(qself, path));
                         try!(self.bump());
                         let end = try!(self.parse_pat_range_end());
                         pat = PatRange(begin, end);
                       }
                       token::OpenDelim(token::Brace) => {
-                        // Parse struct pattern
+                         if qself.is_some() {
+                            let span = self.span;
+                            self.span_err(span,
+                                          "unexpected `{` after qualified path");
+                            self.abort_if_errors();
+                        }
+                       // Parse struct pattern
                         try!(self.bump());
                         let (fields, etc) = try!(self.parse_pat_fields());
                         try!(self.bump());
                         pat = PatStruct(path, fields, etc);
                       }
                       token::OpenDelim(token::Paren) => {
+                        if qself.is_some() {
+                            let span = self.span;
+                            self.span_err(span,
+                                          "unexpected `(` after qualified path");
+                            self.abort_if_errors();
+                        }
                         // Parse tuple struct or enum pattern
                         if self.look_ahead(1, |t| *t == token::DotDot) {
                             // This is a "top constructor only" pat
@@ -3273,6 +3322,10 @@ impl<'a> Parser<'a> {
                             pat = PatEnum(path, Some(args));
                         }
                       }
+                      _ if qself.is_some() => {
+                        // Parse qualified path
+                        pat = PatQPath(qself.unwrap(), path);
+                      }
                       _ => {
                         // Parse nullary enum
                         pat = PatEnum(path, Some(vec![]));
@@ -3514,7 +3567,7 @@ impl<'a> Parser<'a> {
                     }
 
                     // Remainder are line-expr stmts.
-                    let e = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR));
+                    let e = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR));
                     spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID))
                 }
             }
@@ -3523,7 +3576,7 @@ impl<'a> Parser<'a> {
 
     /// Is this expression a successfully-parsed statement?
     fn expr_is_complete(&mut self, e: &Expr) -> bool {
-        self.restrictions.contains(RESTRICTION_STMT_EXPR) &&
+        self.restrictions.contains(Restrictions::RESTRICTION_STMT_EXPR) &&
             !classify::expr_requires_semi_to_be_stmt(e)
     }
 
@@ -3807,8 +3860,37 @@ impl<'a> Parser<'a> {
     fn parse_generic_values_after_lt(&mut self) -> PResult<(Vec<ast::Lifetime>,
                                                             Vec<P<Ty>>,
                                                             Vec<P<TypeBinding>>)> {
+        let span_lo = self.span.lo;
         let lifetimes = try!(self.parse_lifetimes(token::Comma));
 
+        let missing_comma = !lifetimes.is_empty() &&
+                            !self.token.is_like_gt() &&
+                            self.last_token
+                                .as_ref().map_or(true,
+                                                 |x| &**x != &token::Comma);
+
+        if missing_comma {
+
+            let msg = format!("expected `,` or `>` after lifetime \
+                              name, found `{}`",
+                              self.this_token_to_string());
+            self.span_err(self.span, &msg);
+
+            let span_hi = self.span.hi;
+            let span_hi = if self.parse_ty_nopanic().is_ok() {
+                self.span.hi
+            } else {
+                span_hi
+            };
+
+            let msg = format!("did you mean a single argument type &'a Type, \
+                              or did you mean the comma-separated arguments \
+                              'a, Type?");
+            self.span_note(mk_sp(span_lo, span_hi), &msg);
+
+            self.abort_if_errors()
+        }
+
         // First parse types.
         let (types, returned) = try!(self.parse_seq_to_gt_or_return(
             Some(token::Comma),
@@ -4304,6 +4386,8 @@ impl<'a> Parser<'a> {
 
     /// Parse an impl item.
     pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
+        maybe_whole!(no_clone self, NtImplItem);
+
         let mut attrs = self.parse_outer_attributes();
         let lo = self.span.lo;
         let vis = try!(self.parse_visibility());
@@ -4313,6 +4397,14 @@ impl<'a> Parser<'a> {
             let typ = try!(self.parse_ty_sum());
             try!(self.expect(&token::Semi));
             (name, TypeImplItem(typ))
+        } else if try!(self.eat_keyword(keywords::Const)) {
+            let name = try!(self.parse_ident());
+            try!(self.expect(&token::Colon));
+            let typ = try!(self.parse_ty_sum());
+            try!(self.expect(&token::Eq));
+            let expr = try!(self.parse_expr_nopanic());
+            try!(self.commit_expr_expecting(&expr, token::Semi));
+            (name, ConstImplItem(typ, expr))
         } else {
             let (name, inner_attrs, node) = try!(self.parse_impl_method(vis));
             attrs.extend(inner_attrs.into_iter());