diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/ast_map/blocks.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/ast_map/mod.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/ast_util.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 28 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 11 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 215 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 31 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 14 |
9 files changed, 235 insertions, 85 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 07fb6cbe5c6..3b7bfb1043a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -593,6 +593,12 @@ pub enum Pat_ { /// "None" means a * pattern where we don't bind the fields to names. PatEnum(Path, Option<Vec<P<Pat>>>), + /// An associated const named using the qualified path `<T>::CONST` or + /// `<T as Trait>::CONST`. Associated consts from inherent impls can be + /// refered to as simply `T::CONST`, in which case they will end up as + /// PatEnum, and the resolver will have to sort that out. + PatQPath(QSelf, Path), + /// Destructuring of a struct, e.g. `Foo {x, y, ..}` /// The `bool` is `true` in the presence of a `..` PatStruct(Path, Vec<Spanned<FieldPat>>, bool), @@ -1230,6 +1236,7 @@ pub struct TraitItem { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum TraitItem_ { + ConstTraitItem(P<Ty>, Option<P<Expr>>), MethodTraitItem(MethodSig, Option<P<Block>>), TypeTraitItem(TyParamBounds, Option<P<Ty>>), } @@ -1246,6 +1253,7 @@ pub struct ImplItem { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ImplItem_ { + ConstImplItem(P<Ty>, P<Expr>), MethodImplItem(MethodSig, P<Block>), TypeImplItem(P<Ty>), MacImplItem(Mac), diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 1505d1e91b8..36a7f3a9381 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -222,8 +222,7 @@ impl<'a> FnLikeNode<'a> { ast::MethodImplItem(ref sig, ref body) => { method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span) } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => { + _ => { panic!("impl method FnLikeNode that is not fn-like") } } diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 2a9a609ecd1..795391d4009 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -940,6 +940,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { } Some(NodeImplItem(ii)) => { match ii.node { + ConstImplItem(..) => { + format!("assoc const {} in {}{}", + token::get_ident(ii.ident), + map.path_to_string(id), + id_str) + } MethodImplItem(..) => { format!("method {} in {}{}", token::get_ident(ii.ident), @@ -959,9 +965,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { } Some(NodeTraitItem(ti)) => { let kind = match ti.node { + ConstTraitItem(..) => "assoc constant", MethodTraitItem(..) => "trait method", TypeTraitItem(..) => "assoc type", -// ConstTraitItem(..) => "assoc constant" }; format!("{} {} in {}{}", diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 720b2095a90..8471fef3487 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -579,7 +579,7 @@ pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool { } PatMac(_) => panic!("attempted to analyze unexpanded pattern"), PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) | - PatEnum(_, _) => { + PatEnum(_, _) | PatQPath(_, _) => { true } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fa95f667c15..60b1d4797d5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -155,6 +155,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows use of unary negate on unsigned integers, e.g. -e for e: u8 ("negate_unsigned", "1.0.0", Active), + + // Allows the definition of associated constants in `trait` or `impl` + // blocks. + ("associated_consts", "1.0.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -659,6 +663,30 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } visit::walk_fn(self, fn_kind, fn_decl, block, span); } + + fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) { + match ti.node { + ast::ConstTraitItem(..) => { + self.gate_feature("associated_consts", + ti.span, + "associated constants are experimental") + } + _ => {} + } + visit::walk_trait_item(self, ti); + } + + fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) { + match ii.node { + ast::ConstImplItem(..) => { + self.gate_feature("associated_consts", + ii.span, + "associated constants are experimental") + } + _ => {} + } + visit::walk_impl_item(self, ii); + } } fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 5352a191b09..adfda988b23 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -980,6 +980,10 @@ pub fn noop_fold_trait_item<T: Folder>(i: P<TraitItem>, folder: &mut T) ident: folder.fold_ident(ident), attrs: fold_attrs(attrs, folder), node: match node { + ConstTraitItem(ty, default) => { + ConstTraitItem(folder.fold_ty(ty), + default.map(|x| folder.fold_expr(x))) + } MethodTraitItem(sig, body) => { MethodTraitItem(noop_fold_method_sig(sig, folder), body.map(|x| folder.fold_block(x))) @@ -1001,6 +1005,9 @@ pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T) attrs: fold_attrs(attrs, folder), vis: vis, node: match node { + ConstImplItem(ty, expr) => { + ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr)) + } MethodImplItem(sig, body) => { MethodImplItem(noop_fold_method_sig(sig, folder), folder.fold_block(body)) @@ -1134,6 +1141,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> { PatEnum(folder.fold_path(pth), pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) } + PatQPath(qself, pth) => { + let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself}; + PatQPath(qself, folder.fold_path(pth)) + } PatStruct(pth, fields, etc) => { let pth = folder.fold_path(pth); let fs = fields.move_map(|f| { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5f097256318..f76de1f04ce 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}; @@ -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 { @@ -1161,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)) { @@ -1334,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) || @@ -1580,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 @@ -2043,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) ){ @@ -3158,16 +3171,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) } @@ -3243,25 +3265,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 @@ -3278,6 +3319,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![])); @@ -4349,6 +4394,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()); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 36364eb9bf3..87c164f7550 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -761,6 +761,26 @@ impl<'a> State<'a> { } } + fn print_associated_const(&mut self, + ident: ast::Ident, + ty: &ast::Ty, + default: Option<&ast::Expr>, + vis: ast::Visibility) + -> io::Result<()> + { + try!(word(&mut self.s, &visibility_qualified(vis, ""))); + try!(self.word_space("const")); + try!(self.print_ident(ident)); + try!(self.word_space(":")); + try!(self.print_type(ty)); + if let Some(expr) = default { + try!(space(&mut self.s)); + try!(self.word_space("=")); + try!(self.print_expr(expr)); + } + word(&mut self.s, ";") + } + fn print_associated_type(&mut self, ident: ast::Ident, bounds: Option<&ast::TyParamBounds>, @@ -1234,6 +1254,11 @@ impl<'a> State<'a> { try!(self.maybe_print_comment(ti.span.lo)); try!(self.print_outer_attributes(&ti.attrs)); match ti.node { + ast::ConstTraitItem(ref ty, ref default) => { + try!(self.print_associated_const(ti.ident, &ty, + default.as_ref().map(|expr| &**expr), + ast::Inherited)); + } ast::MethodTraitItem(ref sig, ref body) => { if body.is_some() { try!(self.head("")); @@ -1260,6 +1285,9 @@ impl<'a> State<'a> { try!(self.maybe_print_comment(ii.span.lo)); try!(self.print_outer_attributes(&ii.attrs)); match ii.node { + ast::ConstImplItem(ref ty, ref expr) => { + try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis)); + } ast::MethodImplItem(ref sig, ref body) => { try!(self.head("")); try!(self.print_method_sig(ii.ident, sig, ii.vis)); @@ -2152,6 +2180,9 @@ impl<'a> State<'a> { } } } + ast::PatQPath(ref qself, ref path) => { + try!(self.print_qpath(path, qself, false)); + } ast::PatStruct(ref path, ref fields, etc) => { try!(self.print_path(path, true, 0)); try!(self.nbsp()); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4c70fc9f81f..6cf791b10be 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -464,6 +464,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { } } } + PatQPath(ref qself, ref path) => { + visitor.visit_ty(&qself.ty); + visitor.visit_path(path, pattern.id) + } PatStruct(ref path, ref fields, _) => { visitor.visit_path(path, pattern.id); for field in fields { @@ -619,6 +623,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai visitor.visit_attribute(attr); } match trait_item.node { + ConstTraitItem(ref ty, ref default) => { + visitor.visit_ty(ty); + if let Some(ref expr) = *default { + visitor.visit_expr(expr); + } + } MethodTraitItem(ref sig, None) => { visitor.visit_explicit_self(&sig.explicit_self); visitor.visit_generics(&sig.generics); @@ -641,6 +651,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_attribute(attr); } match impl_item.node { + ConstImplItem(ref ty, ref expr) => { + visitor.visit_ty(ty); + visitor.visit_expr(expr); + } MethodImplItem(ref sig, ref body) => { visitor.visit_fn(FkMethod(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl, body, impl_item.span, impl_item.id); |
