diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 646294a7cca78..6586280d21454 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -214,11 +214,18 @@ impl GenericArg { pub struct AngleBracketedArgs { /// The overall span. pub span: Span, - /// The arguments for this path segment. - pub args: Vec, - /// Constraints on associated types, if any. - /// E.g., `Foo`. - pub constraints: Vec, + /// The comma separated parts in the `<...>`. + pub args: Vec, +} + +/// Either an argument for a parameter e.g., `'a`, `Vec`, `0`, +/// or a constraint on an associated item, e.g., `Item = String` or `Item: Bound`. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum AngleBracketedArg { + /// Argument for a generic parameter. + Arg(GenericArg), + /// Constraint for an associated item. + Constraint(AssocTyConstraint), } impl Into>> for AngleBracketedArgs { @@ -248,11 +255,13 @@ pub struct ParenthesizedArgs { impl ParenthesizedArgs { pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs { - AngleBracketedArgs { - span: self.span, - args: self.inputs.iter().cloned().map(GenericArg::Type).collect(), - constraints: vec![], - } + let args = self + .inputs + .iter() + .cloned() + .map(|input| AngleBracketedArg::Arg(GenericArg::Type(input))) + .collect(); + AngleBracketedArgs { span: self.span, args } } } diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index 67f7764d5bb27..a72a60c30b28a 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -546,9 +546,11 @@ pub fn noop_visit_angle_bracketed_parameter_data( data: &mut AngleBracketedArgs, vis: &mut T, ) { - let AngleBracketedArgs { args, constraints, span } = data; - visit_vec(args, |arg| vis.visit_generic_arg(arg)); - visit_vec(constraints, |constraint| vis.visit_ty_constraint(constraint)); + let AngleBracketedArgs { args, span } = data; + visit_vec(args, |arg| match arg { + AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg), + AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint), + }); vis.visit_span(span); } diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs index cc2b1c48b51ac..51863350a8cf3 100644 --- a/src/librustc_ast/visit.rs +++ b/src/librustc_ast/visit.rs @@ -464,8 +464,12 @@ where { match *generic_args { GenericArgs::AngleBracketed(ref data) => { - walk_list!(visitor, visit_generic_arg, &data.args); - walk_list!(visitor, visit_assoc_ty_constraint, &data.constraints); + for arg in &data.args { + match arg { + AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a), + AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c), + } + } } GenericArgs::Parenthesized(ref data) => { walk_list!(visitor, visit_ty, &data.inputs); diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 68cb1f8585fc7..45ee7265c15fc 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -34,6 +34,7 @@ #![feature(crate_visibility_modifier)] #![feature(marker_trait_attr)] #![feature(specialization)] +#![feature(or_patterns)] #![recursion_limit = "256"] use rustc_ast::ast; diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs index e996bdac7cb37..dde734756517c 100644 --- a/src/librustc_ast_lowering/path.rs +++ b/src/librustc_ast_lowering/path.rs @@ -366,22 +366,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode: ParamMode, mut itctx: ImplTraitContext<'_, 'hir>, ) -> (GenericArgsCtor<'hir>, bool) { - let &AngleBracketedArgs { ref args, ref constraints, .. } = data; - let has_non_lt_args = args.iter().any(|arg| match arg { - ast::GenericArg::Lifetime(_) => false, - ast::GenericArg::Type(_) => true, - ast::GenericArg::Const(_) => true, + let has_non_lt_args = data.args.iter().any(|arg| match arg { + AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_)) + | AngleBracketedArg::Constraint(_) => false, + AngleBracketedArg::Arg(ast::GenericArg::Type(_) | ast::GenericArg::Const(_)) => true, }); - ( - GenericArgsCtor { - args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(), - bindings: self.arena.alloc_from_iter( - constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())), - ), - parenthesized: false, - }, - !has_non_lt_args && param_mode == ParamMode::Optional, - ) + let args = data + .args + .iter() + .filter_map(|arg| match arg { + AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx.reborrow())), + AngleBracketedArg::Constraint(_) => None, + }) + .collect(); + let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg { + AngleBracketedArg::Constraint(c) => { + Some(self.lower_assoc_ty_constraint(c, itctx.reborrow())) + } + AngleBracketedArg::Arg(_) => None, + })); + let ctor = GenericArgsCtor { args, bindings, parenthesized: false }; + (ctor, !has_non_lt_args && param_mode == ParamMode::Optional) } fn lower_parenthesized_parameter_data( diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 885f2f939a653..de7ae10723f4d 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -639,6 +639,34 @@ impl<'a> AstValidator<'a> { .emit(); } } + + /// Enforce generic args coming before constraints in `<...>` of a path segment. + fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) { + // Early exit in case it's partitioned as it should be. + if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) { + return; + } + // Find all generic argument coming after the first constraint... + let mut misplaced_args = Vec::new(); + let mut first = None; + for arg in &data.args { + match (arg, first) { + (AngleBracketedArg::Arg(a), Some(_)) => misplaced_args.push(a.span()), + (AngleBracketedArg::Constraint(c), None) => first = Some(c.span), + (AngleBracketedArg::Arg(_), None) | (AngleBracketedArg::Constraint(_), Some(_)) => { + } + } + } + // ...and then error: + self.err_handler() + .struct_span_err( + misplaced_args.clone(), + "generic arguments must come before the first constraint", + ) + .span_label(first.unwrap(), "the first constraint is provided here") + .span_labels(misplaced_args, "generic argument") + .emit(); + } } /// Checks that generic parameters are in the correct order, @@ -1008,17 +1036,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) { match *generic_args { GenericArgs::AngleBracketed(ref data) => { - walk_list!(self, visit_generic_arg, &data.args); - - // Type bindings such as `Item = impl Debug` in `Iterator` - // are allowed to contain nested `impl Trait`. - self.with_impl_trait(None, |this| { - walk_list!( - this, - visit_assoc_ty_constraint_from_generic_args, - &data.constraints - ); - }); + self.check_generic_args_before_constraints(data); + + for arg in &data.args { + match arg { + AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg), + // Type bindings such as `Item = impl Debug` in `Iterator` + // are allowed to contain nested `impl Trait`. + AngleBracketedArg::Constraint(constraint) => { + self.with_impl_trait(None, |this| { + this.visit_assoc_ty_constraint_from_generic_args(constraint); + }); + } + } + } } GenericArgs::Parenthesized(ref data) => { walk_list!(self, visit_ty, &data.inputs); diff --git a/src/librustc_ast_passes/lib.rs b/src/librustc_ast_passes/lib.rs index 10081d36754ba..bfe304419801d 100644 --- a/src/librustc_ast_passes/lib.rs +++ b/src/librustc_ast_passes/lib.rs @@ -1,10 +1,12 @@ -#![feature(bindings_after_at)] //! The `rustc_ast_passes` crate contains passes which validate the AST in `syntax` //! parsed by `rustc_parse` and then lowered, after the passes in this crate, //! by `rustc_ast_lowering`. //! //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`. +#![feature(bindings_after_at)] +#![feature(iter_is_partitioned)] + pub mod ast_validation; pub mod feature_gate; pub mod node_count; diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 2d6932ffbeedf..4aabbe7efbef4 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -796,31 +796,10 @@ impl<'a> PrintState<'a> for State<'a> { match *args { ast::GenericArgs::AngleBracketed(ref data) => { self.s.word("<"); - - self.commasep(Inconsistent, &data.args, |s, generic_arg| { - s.print_generic_arg(generic_arg) + self.commasep(Inconsistent, &data.args, |s, arg| match arg { + ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a), + ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c), }); - - let mut comma = !data.args.is_empty(); - - for constraint in data.constraints.iter() { - if comma { - self.word_space(",") - } - self.print_ident(constraint.ident); - self.s.space(); - match constraint.kind { - ast::AssocTyConstraintKind::Equality { ref ty } => { - self.word_space("="); - self.print_type(ty); - } - ast::AssocTyConstraintKind::Bound { ref bounds } => { - self.print_type_bounds(":", &*bounds); - } - } - comma = true; - } - self.s.word(">") } @@ -891,6 +870,20 @@ impl<'a> State<'a> { } } + fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) { + self.print_ident(constraint.ident); + self.s.space(); + match &constraint.kind { + ast::AssocTyConstraintKind::Equality { ty } => { + self.word_space("="); + self.print_type(ty); + } + ast::AssocTyConstraintKind::Bound { bounds } => { + self.print_type_bounds(":", &*bounds); + } + } + } + crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) { match generic_arg { GenericArg::Lifetime(lt) => self.print_lifetime(*lt), diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index 48ceaf5fccd8e..4d89bf79e7c67 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -36,7 +36,8 @@ impl<'a> ExtCtxt<'a> { idents.into_iter().map(|ident| ast::PathSegment::from_ident(ident.with_span_pos(span))), ); let args = if !args.is_empty() { - ast::AngleBracketedArgs { args, constraints: Vec::new(), span }.into() + let args = args.into_iter().map(ast::AngleBracketedArg::Arg).collect(); + ast::AngleBracketedArgs { args, span }.into() } else { None }; diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index c6f2d1b82fcf4..eff7dacef7953 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -634,17 +634,19 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> { match seg.args.as_ref().map(|generic_arg| &**generic_arg) { None => false, Some(&ast::GenericArgs::AngleBracketed(ref data)) => { - let types = data.args.iter().filter_map(|arg| match arg { - ast::GenericArg::Type(ty) => Some(ty), - _ => None, - }); - any_involves_impl_trait(types) - || data.constraints.iter().any(|c| match c.kind { + data.args.iter().any(|arg| match arg { + ast::AngleBracketedArg::Arg(arg) => match arg { + ast::GenericArg::Type(ty) => involves_impl_trait(ty), + ast::GenericArg::Lifetime(_) + | ast::GenericArg::Const(_) => false, + }, + ast::AngleBracketedArg::Constraint(c) => match c.kind { ast::AssocTyConstraintKind::Bound { .. } => true, ast::AssocTyConstraintKind::Equality { ref ty } => { involves_impl_trait(ty) } - }) + }, + }) } Some(&ast::GenericArgs::Parenthesized(ref data)) => { any_involves_impl_trait(data.inputs.iter()) diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index f88b4fe6ff0a8..9fa7bc027b878 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -1,12 +1,10 @@ use super::ty::{AllowPlus, RecoverQPath}; use super::{Parser, TokenType}; use crate::maybe_whole; -use rustc_ast::ast::{ - self, AngleBracketedArgs, Ident, ParenthesizedArgs, Path, PathSegment, QSelf, -}; -use rustc_ast::ast::{ - AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode, GenericArg, -}; +use rustc_ast::ast::{self, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs}; +use rustc_ast::ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; +use rustc_ast::ast::{Ident, Path, PathSegment, QSelf}; +use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; use rustc_errors::{pluralize, Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; @@ -218,11 +216,11 @@ impl<'a> Parser<'a> { let lo = self.token.span; let args = if self.eat_lt() { // `<'a, T, A = U>` - let (args, constraints) = - self.parse_generic_args_with_leading_angle_bracket_recovery(style, lo)?; + let args = + self.parse_angle_args_with_leading_angle_bracket_recovery(style, lo)?; self.expect_gt()?; let span = lo.to(self.prev_token.span); - AngleBracketedArgs { args, constraints, span }.into() + AngleBracketedArgs { args, span }.into() } else { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; @@ -251,18 +249,18 @@ impl<'a> Parser<'a> { /// Parses generic args (within a path segment) with recovery for extra leading angle brackets. /// For the purposes of understanding the parsing logic of generic arguments, this function - /// can be thought of being the same as just calling `self.parse_generic_args()` if the source + /// can be thought of being the same as just calling `self.parse_angle_args()` if the source /// had the correct amount of leading angle brackets. /// /// ```ignore (diagnostics) /// bar::<<<::Output>(); /// ^^ help: remove extra angle brackets /// ``` - fn parse_generic_args_with_leading_angle_bracket_recovery( + fn parse_angle_args_with_leading_angle_bracket_recovery( &mut self, style: PathStyle, lo: Span, - ) -> PResult<'a, (Vec, Vec)> { + ) -> PResult<'a, Vec> { // We need to detect whether there are extra leading left angle brackets and produce an // appropriate error and suggestion. This cannot be implemented by looking ahead at // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens @@ -337,8 +335,8 @@ impl<'a> Parser<'a> { let snapshot = if is_first_invocation { Some(self.clone()) } else { None }; debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)"); - match self.parse_generic_args() { - Ok(value) => Ok(value), + match self.parse_angle_args() { + Ok(args) => Ok(args), Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { // Cancel error from being unable to find `>`. We know the error // must have been this due to a non-zero unmatched angle bracket @@ -381,110 +379,136 @@ impl<'a> Parser<'a> { .emit(); // Try again without unmatched angle bracket characters. - self.parse_generic_args() + self.parse_angle_args() } Err(e) => Err(e), } } - /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings, + /// Parses (possibly empty) list of generic arguments / associated item constraints, /// possibly including trailing comma. - fn parse_generic_args(&mut self) -> PResult<'a, (Vec, Vec)> { + fn parse_angle_args(&mut self) -> PResult<'a, Vec> { let mut args = Vec::new(); - let mut constraints = Vec::new(); - let mut misplaced_assoc_ty_constraints: Vec = Vec::new(); - let mut assoc_ty_constraints: Vec = Vec::new(); - - let args_lo = self.token.span; - - loop { - if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { - // Parse lifetime argument. - args.push(GenericArg::Lifetime(self.expect_lifetime())); - misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints); - } else if self.check_ident() - && self.look_ahead(1, |t| t == &token::Eq || t == &token::Colon) - { - // Parse associated type constraint. - let lo = self.token.span; - let ident = self.parse_ident()?; - let kind = if self.eat(&token::Eq) { - AssocTyConstraintKind::Equality { ty: self.parse_ty()? } - } else if self.eat(&token::Colon) { - AssocTyConstraintKind::Bound { - bounds: self.parse_generic_bounds(Some(self.prev_token.span))?, - } - } else { - unreachable!(); - }; + while let Some(arg) = self.parse_angle_arg()? { + args.push(arg); + if !self.eat(&token::Comma) { + break; + } + } + Ok(args) + } - let span = lo.to(self.prev_token.span); + /// Parses a single argument in the angle arguments `<...>` of a path segment. + fn parse_angle_arg(&mut self) -> PResult<'a, Option> { + if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon)) + { + // Parse associated type constraint. + let lo = self.token.span; + let ident = self.parse_ident()?; + let kind = if self.eat(&token::Eq) { + let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?; + AssocTyConstraintKind::Equality { ty } + } else if self.eat(&token::Colon) { + let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; + AssocTyConstraintKind::Bound { bounds } + } else { + unreachable!(); + }; - // Gate associated type bounds, e.g., `Iterator`. - if let AssocTyConstraintKind::Bound { .. } = kind { - self.sess.gated_spans.gate(sym::associated_type_bounds, span); - } + let span = lo.to(self.prev_token.span); - constraints.push(AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span }); - assoc_ty_constraints.push(span); - } else if self.check_const_arg() { - // Parse const argument. - let expr = if let token::OpenDelim(token::Brace) = self.token.kind { - self.parse_block_expr( - None, - self.token.span, - BlockCheckMode::Default, - ast::AttrVec::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. - if self.token.is_bool_lit() { - self.parse_literal_maybe_minus()? - } else { - let span = self.token.span; - let msg = "identifiers may currently not be used for const generics"; - self.struct_span_err(span, msg).emit(); - let block = self.mk_block_err(span); - self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new()) - } - } else { - self.parse_literal_maybe_minus()? - }; - let value = AnonConst { id: ast::DUMMY_NODE_ID, value: expr }; - args.push(GenericArg::Const(value)); - misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints); - } else if self.check_type() { - // Parse type argument. - args.push(GenericArg::Type(self.parse_ty()?)); - misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints); - } else { - break; + // Gate associated type bounds, e.g., `Iterator`. + if let AssocTyConstraintKind::Bound { .. } = kind { + self.sess.gated_spans.gate(sym::associated_type_bounds, span); } - if !self.eat(&token::Comma) { - break; - } + let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span }; + Ok(Some(AngleBracketedArg::Constraint(constraint))) + } else { + Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg)) } + } - // 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_constraints.is_empty() { - let mut err = self.struct_span_err( - args_lo.to(self.prev_token.span), - "associated type bindings must be declared after generic parameters", - ); - for span in misplaced_assoc_ty_constraints { - err.span_label( - span, - "this associated type binding should be moved after the generic parameters", - ); + /// Parse the term to the right of an associated item equality constraint. + /// That is, parse `` in `Item = `. + /// Right now, this only admits types in ``. + fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P> { + let arg = self.parse_generic_arg()?; + let span = ident.span.to(self.prev_token.span); + match arg { + Some(GenericArg::Type(ty)) => return Ok(ty), + Some(GenericArg::Const(expr)) => { + self.struct_span_err(span, "cannot constrain an associated constant to a value") + .span_label(ident.span, "this associated constant...") + .span_label(expr.value.span, "...cannot be constrained to this value") + .emit(); + } + Some(GenericArg::Lifetime(lt)) => { + self.struct_span_err(span, "associated lifetimes are not supported") + .span_label(lt.ident.span, "the lifetime is given here") + .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`") + .emit(); + } + None => { + let after_eq = eq.shrink_to_hi(); + let before_next = self.token.span.shrink_to_lo(); + self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`") + .span_suggestion( + self.sess.source_map().next_point(eq).to(before_next), + "to constrain the associated type, add a type after `=`", + " TheType".to_string(), + Applicability::HasPlaceholders, + ) + .span_suggestion( + eq.to(before_next), + &format!("remove the `=` if `{}` is a type", ident), + String::new(), + Applicability::MaybeIncorrect, + ) + .emit(); } - err.emit(); } + Ok(self.mk_ty(span, ast::TyKind::Err)) + } - Ok((args, constraints)) + /// Parse a generic argument in a path segment. + /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`. + fn parse_generic_arg(&mut self) -> PResult<'a, Option> { + let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { + // Parse lifetime argument. + GenericArg::Lifetime(self.expect_lifetime()) + } else if self.check_const_arg() { + // Parse const argument. + let expr = if let token::OpenDelim(token::Brace) = self.token.kind { + self.parse_block_expr( + None, + self.token.span, + BlockCheckMode::Default, + ast::AttrVec::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. + if self.token.is_bool_lit() { + self.parse_literal_maybe_minus()? + } else { + let span = self.token.span; + let msg = "identifiers may currently not be used for const generics"; + self.struct_span_err(span, msg).emit(); + let block = self.mk_block_err(span); + self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new()) + } + } else { + self.parse_literal_maybe_minus()? + }; + GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr }) + } else if self.check_type() { + // Parse type argument. + GenericArg::Type(self.parse_ty()?) + } else { + return Ok(None); + }; + Ok(Some(arg)) } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a80c3b72044ef..0829a82b932c3 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -783,7 +783,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { match **generic_args { ast::GenericArgs::AngleBracketed(ref data) => { for arg in &data.args { - if let ast::GenericArg::Type(ty) = arg { + if let ast::AngleBracketedArg::Arg(ast::GenericArg::Type(ty)) = arg { self.visit_ty(ty); } } @@ -849,7 +849,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args { for arg in &data.args { match arg { - ast::GenericArg::Type(ty) => self.visit_ty(ty), + ast::AngleBracketedArg::Arg(ast::GenericArg::Type(ty)) => self.visit_ty(ty), _ => {} } } diff --git a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs new file mode 100644 index 0000000000000..afbd13e6fd9a8 --- /dev/null +++ b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs @@ -0,0 +1,9 @@ +// check-pass + +#[cfg(FALSE)] +fn syntax() { + foo::(); + foo::(); +} + +fn main() {} diff --git a/src/test/ui/parser/issue-32214.rs b/src/test/ui/parser/issue-32214.rs index 82f7ce62b9457..1379eeb58e6e8 100644 --- a/src/test/ui/parser/issue-32214.rs +++ b/src/test/ui/parser/issue-32214.rs @@ -1,6 +1,6 @@ trait Trait { type Item; } pub fn test >() {} -//~^ ERROR associated type bindings must be declared after generic parameters +//~^ ERROR generic arguments must come before the first constraint fn main() { } diff --git a/src/test/ui/parser/issue-32214.stderr b/src/test/ui/parser/issue-32214.stderr index 08b230a14f50e..742f4fdc38bbd 100644 --- a/src/test/ui/parser/issue-32214.stderr +++ b/src/test/ui/parser/issue-32214.stderr @@ -1,10 +1,10 @@ -error: associated type bindings must be declared after generic parameters - --> $DIR/issue-32214.rs:3:25 +error: generic arguments must come before the first constraint + --> $DIR/issue-32214.rs:3:34 | LL | pub fn test >() {} - | -------^^^ + | ------- ^ generic argument | | - | this associated type binding should be moved after the generic parameters + | the first constraint is provided here error: aborting due to previous error diff --git a/src/test/ui/parser/recover-assoc-const-constraint.rs b/src/test/ui/parser/recover-assoc-const-constraint.rs new file mode 100644 index 0000000000000..06be3cdcc1a95 --- /dev/null +++ b/src/test/ui/parser/recover-assoc-const-constraint.rs @@ -0,0 +1,7 @@ +#[cfg(FALSE)] +fn syntax() { + bar::(); //~ ERROR cannot constrain an associated constant to a value + bar::(); //~ ERROR cannot constrain an associated constant to a value +} + +fn main() {} diff --git a/src/test/ui/parser/recover-assoc-const-constraint.stderr b/src/test/ui/parser/recover-assoc-const-constraint.stderr new file mode 100644 index 0000000000000..c6733b33faa58 --- /dev/null +++ b/src/test/ui/parser/recover-assoc-const-constraint.stderr @@ -0,0 +1,20 @@ +error: cannot constrain an associated constant to a value + --> $DIR/recover-assoc-const-constraint.rs:3:11 + | +LL | bar::(); + | ----^^^-- + | | | + | | ...cannot be constrained to this value + | this associated constant... + +error: cannot constrain an associated constant to a value + --> $DIR/recover-assoc-const-constraint.rs:4:11 + | +LL | bar::(); + | ----^^^------ + | | | + | | ...cannot be constrained to this value + | this associated constant... + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/recover-assoc-eq-missing-term.rs b/src/test/ui/parser/recover-assoc-eq-missing-term.rs new file mode 100644 index 0000000000000..4b42c44dc64e5 --- /dev/null +++ b/src/test/ui/parser/recover-assoc-eq-missing-term.rs @@ -0,0 +1,6 @@ +#[cfg(FALSE)] +fn syntax() { + bar::(); //~ ERROR missing type to the right of `=` +} + +fn main() {} diff --git a/src/test/ui/parser/recover-assoc-eq-missing-term.stderr b/src/test/ui/parser/recover-assoc-eq-missing-term.stderr new file mode 100644 index 0000000000000..6e41e139220ae --- /dev/null +++ b/src/test/ui/parser/recover-assoc-eq-missing-term.stderr @@ -0,0 +1,17 @@ +error: missing type to the right of `=` + --> $DIR/recover-assoc-eq-missing-term.rs:3:17 + | +LL | bar::(); + | ^^^ + | +help: to constrain the associated type, add a type after `=` + | +LL | bar::(); + | ^^^^^^^ +help: remove the `=` if `Item` is a type + | +LL | bar::(); + | -- + +error: aborting due to previous error + diff --git a/src/test/ui/parser/recover-assoc-lifetime-constraint.rs b/src/test/ui/parser/recover-assoc-lifetime-constraint.rs new file mode 100644 index 0000000000000..558fcdfe1776f --- /dev/null +++ b/src/test/ui/parser/recover-assoc-lifetime-constraint.rs @@ -0,0 +1,6 @@ +#[cfg(FALSE)] +fn syntax() { + bar::(); //~ ERROR associated lifetimes are not supported +} + +fn main() {} diff --git a/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr b/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr new file mode 100644 index 0000000000000..79437533d7c0b --- /dev/null +++ b/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr @@ -0,0 +1,12 @@ +error: associated lifetimes are not supported + --> $DIR/recover-assoc-lifetime-constraint.rs:3:11 + | +LL | bar::(); + | ^^^^^^^-- + | | + | the lifetime is given here + | + = help: if you meant to specify a trait object, write `dyn Trait + 'lifetime` + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/suggest-move-types.rs b/src/test/ui/suggestions/suggest-move-types.rs index 6505a97de6e4b..27930626a6209 100644 --- a/src/test/ui/suggestions/suggest-move-types.rs +++ b/src/test/ui/suggestions/suggest-move-types.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![allow(warnings)] // This test verifies that the suggestion to move types before associated type bindings @@ -25,20 +23,22 @@ trait ThreeWithLifetime<'a, 'b, 'c, T, U, V> { type C; } -struct A> { //~ ERROR associated type bindings must be declared after generic parameters +struct A> { +//~^ ERROR generic arguments must come before the first constraint m: M, t: T, } struct Al<'a, T, M: OneWithLifetime> { -//~^ ERROR associated type bindings must be declared after generic parameters +//~^ ERROR generic arguments must come before the first constraint //~^^ ERROR type provided when a lifetime was expected m: M, t: &'a T, } -struct B> { //~ ERROR associated type bindings must be declared after generic parameters +struct B> { +//~^ ERROR generic arguments must come before the first constraint m: M, t: T, u: U, @@ -46,7 +46,7 @@ struct B> { //~ ERROR associated ty } struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { -//~^ ERROR associated type bindings must be declared after generic parameters +//~^ ERROR generic arguments must come before the first constraint //~^^ ERROR type provided when a lifetime was expected m: M, t: &'a T, @@ -54,7 +54,8 @@ struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { //~ ERROR associated type bindings must be declared after generic parameters +struct C> { +//~^ ERROR generic arguments must come before the first constraint m: M, t: T, u: U, @@ -62,7 +63,7 @@ struct C> { //~ ERROR associated ty } struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { -//~^ ERROR associated type bindings must be declared after generic parameters +//~^ ERROR generic arguments must come before the first constraint //~^^ ERROR lifetime provided when a type was expected m: M, t: &'a T, @@ -70,7 +71,8 @@ struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { //~ ERROR associated type bindings must be declared after generic parameters +struct D> { +//~^ ERROR generic arguments must come before the first constraint m: M, t: T, u: U, @@ -78,7 +80,7 @@ struct D> { //~ ERROR associated ty } struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { -//~^ ERROR associated type bindings must be declared after generic parameters +//~^ ERROR generic arguments must come before the first constraint //~^^ ERROR lifetime provided when a type was expected m: M, t: &'a T, diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index ac91813f92839..4dd0613757a95 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -1,81 +1,85 @@ -error: associated type bindings must be declared after generic parameters - --> $DIR/suggest-move-types.rs:28:20 +error: generic arguments must come before the first constraint + --> $DIR/suggest-move-types.rs:26:26 | LL | struct A> { - | ----^^^ + | ---- ^ generic argument | | - | this associated type binding should be moved after the generic parameters + | the first constraint is provided here -error: associated type bindings must be declared after generic parameters - --> $DIR/suggest-move-types.rs:34:37 +error: generic arguments must come before the first constraint + --> $DIR/suggest-move-types.rs:33:43 | LL | struct Al<'a, T, M: OneWithLifetime> { - | ----^^^^^^^ - | | - | this associated type binding should be moved after the generic parameters + | ---- ^ ^^ generic argument + | | | + | | generic argument + | the first constraint is provided here -error: associated type bindings must be declared after generic parameters - --> $DIR/suggest-move-types.rs:41:28 +error: generic arguments must come before the first constraint + --> $DIR/suggest-move-types.rs:40:46 | LL | struct B> { - | ----^^----^^----^^^^^^^^^ - | | | | - | | | this associated type binding should be moved after the generic parameters - | | this associated type binding should be moved after the generic parameters - | this associated type binding should be moved after the generic parameters + | ---- ^ ^ ^ generic argument + | | | | + | | | generic argument + | | generic argument + | the first constraint is provided here -error: associated type bindings must be declared after generic parameters - --> $DIR/suggest-move-types.rs:48:53 +error: generic arguments must come before the first constraint + --> $DIR/suggest-move-types.rs:48:71 | LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ----^^----^^----^^^^^^^^^^^^^^^^^^^^^ - | | | | - | | | this associated type binding should be moved after the generic parameters - | | this associated type binding should be moved after the generic parameters - | this associated type binding should be moved after the generic parameters + | ---- ^ ^ ^ ^^ ^^ ^^ generic argument + | | | | | | | + | | | | | | generic argument + | | | | | generic argument + | | | | generic argument + | | | generic argument + | | generic argument + | the first constraint is provided here -error: associated type bindings must be declared after generic parameters - --> $DIR/suggest-move-types.rs:57:28 +error: generic arguments must come before the first constraint + --> $DIR/suggest-move-types.rs:57:49 | LL | struct C> { - | ^^^----^^----^^----^^^^^^ - | | | | - | | | this associated type binding should be moved after the generic parameters - | | this associated type binding should be moved after the generic parameters - | this associated type binding should be moved after the generic parameters + | ---- ^ ^ generic argument + | | | + | | generic argument + | the first constraint is provided here -error: associated type bindings must be declared after generic parameters - --> $DIR/suggest-move-types.rs:64:53 +error: generic arguments must come before the first constraint + --> $DIR/suggest-move-types.rs:65:78 | LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ^^^^^^^----^^----^^----^^^^^^^^^^^^^^ - | | | | - | | | this associated type binding should be moved after the generic parameters - | | this associated type binding should be moved after the generic parameters - | this associated type binding should be moved after the generic parameters + | ---- ^ ^^ ^ ^^ generic argument + | | | | | + | | | | generic argument + | | | generic argument + | | generic argument + | the first constraint is provided here -error: associated type bindings must be declared after generic parameters - --> $DIR/suggest-move-types.rs:73:28 +error: generic arguments must come before the first constraint + --> $DIR/suggest-move-types.rs:74:43 | LL | struct D> { - | ^^^----^^----^^^^^----^^^ - | | | | - | | | this associated type binding should be moved after the generic parameters - | | this associated type binding should be moved after the generic parameters - | this associated type binding should be moved after the generic parameters + | ---- ^ ^ generic argument + | | | + | | generic argument + | the first constraint is provided here -error: associated type bindings must be declared after generic parameters - --> $DIR/suggest-move-types.rs:80:53 +error: generic arguments must come before the first constraint + --> $DIR/suggest-move-types.rs:82:72 | LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ^^^^^^^----^^----^^^^^^^^^----^^^^^^^ - | | | | - | | | this associated type binding should be moved after the generic parameters - | | this associated type binding should be moved after the generic parameters - | this associated type binding should be moved after the generic parameters + | ---- ^ ^^ ^ ^^ generic argument + | | | | | + | | | | generic argument + | | | generic argument + | | generic argument + | the first constraint is provided here error[E0747]: type provided when a lifetime was expected - --> $DIR/suggest-move-types.rs:34:43 + --> $DIR/suggest-move-types.rs:33:43 | LL | struct Al<'a, T, M: OneWithLifetime> { | ^ @@ -91,7 +95,7 @@ LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime $DIR/suggest-move-types.rs:64:56 + --> $DIR/suggest-move-types.rs:65:56 | LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { | ^^ @@ -99,7 +103,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime $DIR/suggest-move-types.rs:80:56 + --> $DIR/suggest-move-types.rs:82:56 | LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { | ^^