diff options
| author | bors <bors@rust-lang.org> | 2015-04-27 16:45:21 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-04-27 16:45:21 +0000 |
| commit | 857ef6e272e5634cb9f3e6ee50eb6bc2a2e71651 (patch) | |
| tree | 4ac530a87a187d61ae509897694089d908050033 /src/libsyntax | |
| parent | 32f9f4276271bac1b8c3bc569ceed5cfaf992f29 (diff) | |
| parent | 4c0ac6d5ef8aed2cbe0cc687d5e7f8a8c04961a3 (diff) | |
| download | rust-857ef6e272e5634cb9f3e6ee50eb6bc2a2e71651.tar.gz rust-857ef6e272e5634cb9f3e6ee50eb6bc2a2e71651.zip | |
Auto merge of #23606 - quantheory:associated_const, r=nikomatsakis
Closes #17841. The majority of the work should be done, e.g. trait and inherent impls, different forms of UFCS syntax, defaults, and cross-crate usage. It's probably enough to replace the constants in `f32`, `i8`, and so on, or close to good enough. There is still some significant functionality missing from this commit: - ~~Associated consts can't be used in match patterns at all. This is simply because I haven't updated the relevant bits in the parser or `resolve`, but it's *probably* not hard to get working.~~ - Since you can't select an impl for trait-associated consts until partway through type-checking, there are some problems with code that assumes that you can check constants earlier. Associated consts that are not in inherent impls cause ICEs if you try to use them in array sizes or match ranges. For similar reasons, `check_static_recursion` doesn't check them properly, so the stack goes ka-blooey if you use an associated constant that's recursively defined. That's a bit trickier to solve; I'm not entirely sure what the best approach is yet. - Dealing with consts associated with type parameters will raise some new issues (e.g. if you have a `T: Int` type parameter and want to use `<T>::ZERO`). See rust-lang/rfcs#865. - ~~Unused associated consts don't seem to trigger the `dead_code` lint when they should. Probably easy to fix.~~ Also, this is the first time I've been spelunking in rustc to such a large extent, so I've probably done some silly things in a couple of places.
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); |
