diff options
| author | bors <bors@rust-lang.org> | 2019-02-08 05:50:16 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-02-08 05:50:16 +0000 |
| commit | 43e04fb5522642b6b5230592934e9ee100f2fd56 (patch) | |
| tree | 2c850f35dba2f93a76e2c624bd0a99fd6e2f4e25 /src/libsyntax | |
| parent | d1731801163df1d3a8d4ddfa68adac2ec833ef7f (diff) | |
| parent | f2fe71c02ac7ecb29106b1a826d657ff5705ad6c (diff) | |
| download | rust-43e04fb5522642b6b5230592934e9ee100f2fd56.tar.gz rust-43e04fb5522642b6b5230592934e9ee100f2fd56.zip | |
Auto merge of #58191 - varkor:const-generics-ast, r=petrochenkov
Add const generics to the AST This is mostly split out from https://github.com/rust-lang/rust/pull/53645 in an effort to make progress merging const generics piecewise instead of in one go. cc @yodaldevoid, @petrochenkov r? @eddyb
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 36 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 20 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 15 | ||||
| -rw-r--r-- | src/libsyntax/mut_visit.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 288 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 16 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 2 |
8 files changed, 206 insertions, 187 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2cfe2cc896c..681d8eeaa0d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -167,6 +167,17 @@ impl GenericArgs { pub enum GenericArg { Lifetime(Lifetime), Type(P<Ty>), + Const(AnonConst), +} + +impl GenericArg { + pub fn span(&self) -> Span { + match self { + GenericArg::Lifetime(lt) => lt.ident.span, + GenericArg::Type(ty) => ty.span, + GenericArg::Const(ct) => ct.value.span, + } + } } /// A path like `Foo<'a, T>` @@ -296,13 +307,32 @@ impl GenericBound { pub type GenericBounds = Vec<GenericBound>; +/// Specifies the enforced ordering for generic parameters. In the future, +/// if we wanted to relax this order, we could override `PartialEq` and +/// `PartialOrd`, to allow the kinds to be unordered. +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] +pub enum ParamKindOrd { + Lifetime, + Type, + Const, +} + +impl fmt::Display for ParamKindOrd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ParamKindOrd::Lifetime => "lifetime".fmt(f), + ParamKindOrd::Type => "type".fmt(f), + ParamKindOrd::Const => "const".fmt(f), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum GenericParamKind { /// A lifetime definition (e.g., `'a: 'b + 'c + 'd`). Lifetime, - Type { - default: Option<P<Ty>>, - }, + Type { default: Option<P<Ty>> }, + Const { ty: P<Ty> }, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 1e83f6c03ec..6708e3c12a0 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -38,12 +38,14 @@ pub trait AstBuilder { bindings: Vec<ast::TypeBinding>) -> (ast::QSelf, ast::Path); - // types + // types and consts fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy; fn ty(&self, span: Span, ty: ast::TyKind) -> P<ast::Ty>; fn ty_path(&self, path: ast::Path) -> P<ast::Ty>; fn ty_ident(&self, span: Span, idents: ast::Ident) -> P<ast::Ty>; + fn anon_const(&self, span: Span, expr: ast::ExprKind) -> ast::AnonConst; + fn const_ident(&self, span: Span, idents: ast::Ident) -> ast::AnonConst; fn ty_rptr(&self, span: Span, ty: P<ast::Ty>, @@ -394,6 +396,22 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.ty_path(self.path_ident(span, ident)) } + fn anon_const(&self, span: Span, expr: ast::ExprKind) -> ast::AnonConst { + ast::AnonConst { + id: ast::DUMMY_NODE_ID, + value: P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: expr, + span, + attrs: ThinVec::new(), + }) + } + } + + fn const_ident(&self, span: Span, ident: ast::Ident) -> ast::AnonConst { + self.anon_const(span, ast::ExprKind::Path(None, self.path_ident(span, ident))) + } + fn ty_rptr(&self, span: Span, ty: P<ast::Ty>, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e7b9a884b5e..0853b4399d2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -15,7 +15,7 @@ use AttributeType::*; use AttributeGate::*; -use crate::ast::{self, NodeId, PatKind, RangeEnd}; +use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd}; use crate::attr; use crate::early_buffered_lints::BufferedEarlyLintId; use crate::source_map::Spanned; @@ -462,6 +462,9 @@ declare_features! ( // Re-Rebalance coherence (active, re_rebalance_coherence, "1.32.0", Some(55437), None), + // Const generic types. + (active, const_generics, "1.34.0", Some(44580), None), + // #[optimize(X)] (active, optimize_attribute, "1.34.0", Some(54882), None), @@ -1899,6 +1902,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_fn(self, fn_kind, fn_decl, span); } + fn visit_generic_param(&mut self, param: &'a GenericParam) { + if let GenericParamKind::Const { .. } = param.kind { + gate_feature_post!(&self, const_generics, param.ident.span, + "const generics are unstable"); + } + visit::walk_generic_param(self, param); + } + fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { match ti.node { ast::TraitItemKind::Method(ref sig, ref block) => { @@ -1984,7 +1995,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], // Some features are known to be incomplete and using them is likely to have // unanticipated results, such as compiler crashes. We warn the user about these // to alert them. - let incomplete_features = ["generic_associated_types"]; + let incomplete_features = ["generic_associated_types", "const_generics"]; let mut features = Features::new(); let mut edition_enabled_features = FxHashMap::default(); diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 0fd8bbf100f..1e5eb0992bd 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -480,6 +480,7 @@ pub fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T) match arg { GenericArg::Lifetime(lt) => vis.visit_lifetime(lt), GenericArg::Type(ty) => vis.visit_ty(ty), + GenericArg::Const(ct) => vis.visit_anon_const(ct), } } @@ -698,6 +699,9 @@ pub fn noop_visit_generic_param<T: MutVisitor>(param: &mut GenericParam, vis: &m GenericParamKind::Type { default } => { visit_opt(default, |default| vis.visit_ty(default)); } + GenericParamKind::Const { ty } => { + vis.visit_ty(ty); + } } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cacdab980fa..d71145893c3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -397,6 +397,7 @@ crate enum TokenType { Ident, Path, Type, + Const, } impl TokenType { @@ -409,6 +410,7 @@ impl TokenType { TokenType::Ident => "identifier".to_string(), TokenType::Path => "path".to_string(), TokenType::Type => "type".to_string(), + TokenType::Const => "const".to_string(), } } } @@ -946,6 +948,15 @@ impl<'a> Parser<'a> { } } + fn check_const_arg(&mut self) -> bool { + if self.token.can_begin_const_arg() { + true + } else { + self.expected_tokens.push(TokenType::Const); + false + } + } + /// Expect and consume a `+`. if `+=` is seen, replace it with a `=` /// and continue. If a `+` is not seen, return false. /// @@ -1031,7 +1042,8 @@ impl<'a> Parser<'a> { } /// Attempt to consume a `<`. If `<<` is seen, replace it with a single - /// `<` and continue. If a `<` is not seen, return false. + /// `<` and continue. If `<-` is seen, replace it with a single `<` + /// and continue. If a `<` is not seen, return false. /// /// This is meant to be used when parsing generics on a path to get the /// starting token. @@ -1047,6 +1059,11 @@ impl<'a> Parser<'a> { self.bump_with(token::Lt, span); true } + token::LArrow => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + self.bump_with(token::BinOp(token::Minus), span); + true + } _ => false, }; @@ -5482,15 +5499,27 @@ impl<'a> Parser<'a> { Ok((ident, TraitItemKind::Type(bounds, default), generics)) } + fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> { + self.expect_keyword(keywords::Const)?; + let ident = self.parse_ident()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + + Ok(GenericParam { + ident, + id: ast::DUMMY_NODE_ID, + attrs: preceding_attrs.into(), + bounds: Vec::new(), + kind: GenericParamKind::Const { + ty, + } + }) + } + /// Parses (possibly empty) list of lifetime and type parameters, possibly including /// trailing comma and erroneous trailing attributes. crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> { - let mut lifetimes = Vec::new(); let mut params = Vec::new(); - let mut seen_ty_param: Option<Span> = None; - let mut last_comma_span = None; - let mut bad_lifetime_pos = vec![]; - let mut suggestions = vec![]; loop { let attrs = self.parse_outer_attributes()?; if self.check_lifetime() { @@ -5501,39 +5530,40 @@ impl<'a> Parser<'a> { } else { Vec::new() }; - lifetimes.push(ast::GenericParam { + params.push(ast::GenericParam { ident: lifetime.ident, id: lifetime.id, attrs: attrs.into(), bounds, kind: ast::GenericParamKind::Lifetime, }); - if let Some(sp) = seen_ty_param { - let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span); - bad_lifetime_pos.push(self.prev_span); - if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) { - suggestions.push((remove_sp, String::new())); - suggestions.push(( - sp.shrink_to_lo(), - format!("{}, ", snippet))); - } - } + } else if self.check_keyword(keywords::Const) { + // Parse const parameter. + params.push(self.parse_const_param(attrs)?); } else if self.check_ident() { // Parse type parameter. params.push(self.parse_ty_param(attrs)?); - if seen_ty_param.is_none() { - seen_ty_param = Some(self.prev_span); - } } else { // Check for trailing attributes and stop parsing. if !attrs.is_empty() { - let param_kind = if seen_ty_param.is_some() { "type" } else { "lifetime" }; - self.struct_span_err( - attrs[0].span, - &format!("trailing attribute after {} parameters", param_kind), - ) - .span_label(attrs[0].span, "attributes must go before parameters") - .emit(); + if !params.is_empty() { + self.struct_span_err( + attrs[0].span, + &format!("trailing attribute after generic parameter"), + ) + .span_label(attrs[0].span, "attributes must go before parameters") + .emit(); + } else { + self.struct_span_err( + attrs[0].span, + &format!("attribute without generic parameters"), + ) + .span_label( + attrs[0].span, + "attributes are only permitted when preceding parameters", + ) + .emit(); + } } break } @@ -5541,24 +5571,8 @@ impl<'a> Parser<'a> { if !self.eat(&token::Comma) { break } - last_comma_span = Some(self.prev_span); } - if !bad_lifetime_pos.is_empty() { - let mut err = self.struct_span_err( - bad_lifetime_pos, - "lifetime parameters must be declared prior to type parameters", - ); - if !suggestions.is_empty() { - err.multipart_suggestion( - "move the lifetime parameter prior to the first type parameter", - suggestions, - Applicability::MachineApplicable, - ); - } - err.emit(); - } - lifetimes.extend(params); // ensure the correct order of lifetimes and type params - Ok(lifetimes) + Ok(params) } /// Parse a set of optional generic type parameter declarations. Where @@ -5740,35 +5754,16 @@ impl<'a> Parser<'a> { fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> { let mut args = Vec::new(); let mut bindings = Vec::new(); + let mut misplaced_assoc_ty_bindings: Vec<Span> = Vec::new(); + let mut assoc_ty_bindings: Vec<Span> = Vec::new(); - let mut seen_type = false; - let mut seen_binding = false; - - let mut last_comma_span = None; - let mut first_type_or_binding_span: Option<Span> = None; - let mut first_binding_span: Option<Span> = None; + let args_lo = self.span; - let mut bad_lifetime_pos = vec![]; - let mut bad_type_pos = vec![]; - - let mut lifetime_suggestions = vec![]; - let mut type_suggestions = vec![]; loop { if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. args.push(GenericArg::Lifetime(self.expect_lifetime())); - - if seen_type || seen_binding { - let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span); - bad_lifetime_pos.push(self.prev_span); - - if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) { - lifetime_suggestions.push((remove_sp, String::new())); - lifetime_suggestions.push(( - first_type_or_binding_span.unwrap().shrink_to_lo(), - format!("{}, ", snippet))); - } - } + misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings); } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. let lo = self.span; @@ -5782,131 +5777,64 @@ impl<'a> Parser<'a> { ty, span, }); - - seen_binding = true; - if first_type_or_binding_span.is_none() { - first_type_or_binding_span = Some(span); - } - if first_binding_span.is_none() { - first_binding_span = Some(span); - } + assoc_ty_bindings.push(span); + } else if self.check_const_arg() { + // FIXME(const_generics): to distinguish between idents for types and consts, + // we should introduce a GenericArg::Ident in the AST and distinguish when + // lowering to the HIR. For now, idents for const args are not permitted. + + // Parse const argument. + let expr = if let token::OpenDelim(token::Brace) = self.token { + self.parse_block_expr(None, self.span, BlockCheckMode::Default, ThinVec::new())? + } else if self.token.is_ident() { + // FIXME(const_generics): to distinguish between idents for types and consts, + // we should introduce a GenericArg::Ident in the AST and distinguish when + // lowering to the HIR. For now, idents for const args are not permitted. + return Err( + self.fatal("identifiers may currently not be used for const generics") + ); + } else { + // FIXME(const_generics): this currently conflicts with emplacement syntax + // with negative integer literals. + self.parse_literal_maybe_minus()? + }; + let value = AnonConst { + id: ast::DUMMY_NODE_ID, + value: expr, + }; + args.push(GenericArg::Const(value)); + misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings); } else if self.check_type() { // Parse type argument. - let ty_param = self.parse_ty()?; - if seen_binding { - let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span); - bad_type_pos.push(self.prev_span); - - if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) { - type_suggestions.push((remove_sp, String::new())); - type_suggestions.push(( - first_binding_span.unwrap().shrink_to_lo(), - format!("{}, ", snippet))); - } - } - - if first_type_or_binding_span.is_none() { - first_type_or_binding_span = Some(ty_param.span); - } - args.push(GenericArg::Type(ty_param)); - seen_type = true; + args.push(GenericArg::Type(self.parse_ty()?)); + misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings); } else { break } if !self.eat(&token::Comma) { break - } else { - last_comma_span = Some(self.prev_span); - } - } - - self.maybe_report_incorrect_generic_argument_order( - bad_lifetime_pos, bad_type_pos, lifetime_suggestions, type_suggestions - ); - - Ok((args, bindings)) - } - - /// Maybe report an error about incorrect generic argument order - "lifetime parameters - /// must be declared before type parameters", "type parameters must be declared before - /// associated type bindings" or both. - fn maybe_report_incorrect_generic_argument_order( - &self, - bad_lifetime_pos: Vec<Span>, - bad_type_pos: Vec<Span>, - lifetime_suggestions: Vec<(Span, String)>, - type_suggestions: Vec<(Span, String)>, - ) { - let mut err = if !bad_lifetime_pos.is_empty() && !bad_type_pos.is_empty() { - let mut positions = bad_lifetime_pos.clone(); - positions.extend_from_slice(&bad_type_pos); - - self.struct_span_err( - positions, - "generic arguments must declare lifetimes, types and associated type bindings in \ - that order", - ) - } else if !bad_lifetime_pos.is_empty() { - self.struct_span_err( - bad_lifetime_pos.clone(), - "lifetime parameters must be declared prior to type parameters" - ) - } else if !bad_type_pos.is_empty() { - self.struct_span_err( - bad_type_pos.clone(), - "type parameters must be declared prior to associated type bindings" - ) - } else { - return; - }; - - if !bad_lifetime_pos.is_empty() { - for sp in &bad_lifetime_pos { - err.span_label(*sp, "must be declared prior to type parameters"); } } - if !bad_type_pos.is_empty() { - for sp in &bad_type_pos { - err.span_label(*sp, "must be declared prior to associated type bindings"); - } - } - - if !lifetime_suggestions.is_empty() && !type_suggestions.is_empty() { - let mut suggestions = lifetime_suggestions; - suggestions.extend_from_slice(&type_suggestions); - - let plural = bad_lifetime_pos.len() + bad_type_pos.len() > 1; - err.multipart_suggestion( - &format!( - "move the parameter{}", - if plural { "s" } else { "" }, - ), - suggestions, - Applicability::MachineApplicable, - ); - } else if !lifetime_suggestions.is_empty() { - err.multipart_suggestion( - &format!( - "move the lifetime parameter{} prior to the first type parameter", - if bad_lifetime_pos.len() > 1 { "s" } else { "" }, - ), - lifetime_suggestions, - Applicability::MachineApplicable, - ); - } else if !type_suggestions.is_empty() { - err.multipart_suggestion( - &format!( - "move the type parameter{} prior to the first associated type binding", - if bad_type_pos.len() > 1 { "s" } else { "" }, - ), - type_suggestions, - Applicability::MachineApplicable, + // FIXME: we would like to report this in ast_validation instead, but we currently do not + // preserve ordering of generic parameters with respect to associated type binding, so we + // lose that information after parsing. + if misplaced_assoc_ty_bindings.len() > 0 { + let mut err = self.struct_span_err( + args_lo.to(self.prev_span), + "associated type bindings must be declared after generic parameters", ); + for span in misplaced_assoc_ty_bindings { + err.span_label( + span, + "this associated type binding should be moved after the generic parameters", + ); + } + err.emit(); } - err.emit(); + Ok((args, bindings)) } /// Parses an optional `where` clause and places it in `generics`. @@ -6526,6 +6454,7 @@ impl<'a> Parser<'a> { // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds // `<` (LIFETIME|IDENT) `=` - generic parameter with a default + // `<` const - generic const parameter // The only truly ambiguous case is // `<` IDENT `>` `::` IDENT ... // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) @@ -6535,7 +6464,8 @@ impl<'a> Parser<'a> { (self.look_ahead(1, |t| t == &token::Pound || t == &token::Gt) || self.look_ahead(1, |t| t.is_lifetime() || t.is_ident()) && self.look_ahead(2, |t| t == &token::Gt || t == &token::Comma || - t == &token::Colon || t == &token::Eq)) + t == &token::Colon || t == &token::Eq) || + self.look_ahead(1, |t| t.is_keyword(keywords::Const))) } fn parse_impl_body(&mut self) -> PResult<'a, (Vec<ImplItem>, Vec<Attribute>)> { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 3b1fa5ea01f..d5856c67156 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -279,6 +279,20 @@ impl Token { } } + /// Returns `true` if the token can appear at the start of a const param. + pub fn can_begin_const_arg(&self) -> bool { + match self { + OpenDelim(Brace) => true, + Interpolated(ref nt) => match nt.0 { + NtExpr(..) => true, + NtBlock(..) => true, + NtLiteral(..) => true, + _ => false, + } + _ => self.can_begin_literal_or_bool(), + } + } + /// Returns `true` if the token can appear at the start of a generic bound. crate fn can_begin_bound(&self) -> bool { self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) || @@ -293,7 +307,7 @@ impl Token { } } - /// Returns `true` if the token is any literal, a minus (which can follow a literal, + /// Returns `true` if the token is any literal, a minus (which can prefix a literal, /// for example a '-42', or one of the boolean idents). crate fn can_begin_literal_or_bool(&self) -> bool { match *self { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c7c4c4f1620..c670f47b597 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1025,6 +1025,7 @@ impl<'a> State<'a> { match generic_arg { GenericArg::Lifetime(lt) => self.print_lifetime(*lt), GenericArg::Type(ty) => self.print_type(ty), + GenericArg::Const(ct) => self.print_expr(&ct.value), } } @@ -2929,7 +2930,7 @@ impl<'a> State<'a> { s.print_outer_attributes_inline(¶m.attrs)?; let lt = ast::Lifetime { id: param.id, ident: param.ident }; s.print_lifetime_bounds(lt, ¶m.bounds) - }, + } ast::GenericParamKind::Type { ref default } => { s.print_outer_attributes_inline(¶m.attrs)?; s.print_ident(param.ident)?; @@ -2943,6 +2944,15 @@ impl<'a> State<'a> { _ => Ok(()) } } + ast::GenericParamKind::Const { ref ty } => { + s.print_outer_attributes_inline(¶m.attrs)?; + s.word_space("const")?; + s.print_ident(param.ident)?; + s.s.space()?; + s.word_space(":")?; + s.print_type(ty)?; + s.print_type_bounds(":", ¶m.bounds) + } } })?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index acbb58a66b6..bb3b0ea7359 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -126,6 +126,7 @@ pub trait Visitor<'ast>: Sized { match generic_arg { GenericArg::Lifetime(lt) => self.visit_lifetime(lt), GenericArg::Type(ty) => self.visit_ty(ty), + GenericArg::Const(ct) => self.visit_anon_const(ct), } } fn visit_assoc_type_binding(&mut self, type_binding: &'ast TypeBinding) { @@ -486,6 +487,7 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Generi match param.kind { GenericParamKind::Lifetime => {} GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default), + GenericParamKind::Const { ref ty, .. } => visitor.visit_ty(ty), } } |
