Skip to content

Commit b9d5ee5

Browse files
committedMar 28, 2020
Auto merge of #70261 - Centril:angle-args-partition, r=varkor
Move arg/constraint partition check to validation & improve recovery - In the first commit, we move the check rejecting e.g., `<'a, Item = u8, String>` from the parser into AST validation. - We then use this to improve the code for parsing generic arguments. - And we add recovery for e.g., `<Item = >` (missing), `<Item = 42>` (constant), and `<Item = 'a>` (lifetime). This is also preparatory work for supporting #70256. r? @varkor
·
1.87.01.44.0
2 parents b76238a + 42c5cfd commit b9d5ee5

23 files changed

+404
-247
lines changed
 

‎src/librustc_ast/ast.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,18 @@ impl GenericArg {
214214
pub struct AngleBracketedArgs {
215215
/// The overall span.
216216
pub span: Span,
217-
/// The arguments for this path segment.
218-
pub args: Vec<GenericArg>,
219-
/// Constraints on associated types, if any.
220-
/// E.g., `Foo<A = Bar, B: Baz>`.
221-
pub constraints: Vec<AssocTyConstraint>,
217+
/// The comma separated parts in the `<...>`.
218+
pub args: Vec<AngleBracketedArg>,
219+
}
220+
221+
/// Either an argument for a parameter e.g., `'a`, `Vec<u8>`, `0`,
222+
/// or a constraint on an associated item, e.g., `Item = String` or `Item: Bound`.
223+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
224+
pub enum AngleBracketedArg {
225+
/// Argument for a generic parameter.
226+
Arg(GenericArg),
227+
/// Constraint for an associated item.
228+
Constraint(AssocTyConstraint),
222229
}
223230

224231
impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
@@ -248,11 +255,13 @@ pub struct ParenthesizedArgs {
248255

249256
impl ParenthesizedArgs {
250257
pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
251-
AngleBracketedArgs {
252-
span: self.span,
253-
args: self.inputs.iter().cloned().map(GenericArg::Type).collect(),
254-
constraints: vec![],
255-
}
258+
let args = self
259+
.inputs
260+
.iter()
261+
.cloned()
262+
.map(|input| AngleBracketedArg::Arg(GenericArg::Type(input)))
263+
.collect();
264+
AngleBracketedArgs { span: self.span, args }
256265
}
257266
}
258267

‎src/librustc_ast/mut_visit.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -546,9 +546,11 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
546546
data: &mut AngleBracketedArgs,
547547
vis: &mut T,
548548
) {
549-
let AngleBracketedArgs { args, constraints, span } = data;
550-
visit_vec(args, |arg| vis.visit_generic_arg(arg));
551-
visit_vec(constraints, |constraint| vis.visit_ty_constraint(constraint));
549+
let AngleBracketedArgs { args, span } = data;
550+
visit_vec(args, |arg| match arg {
551+
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
552+
AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint),
553+
});
552554
vis.visit_span(span);
553555
}
554556

‎src/librustc_ast/visit.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,8 +464,12 @@ where
464464
{
465465
match *generic_args {
466466
GenericArgs::AngleBracketed(ref data) => {
467-
walk_list!(visitor, visit_generic_arg, &data.args);
468-
walk_list!(visitor, visit_assoc_ty_constraint, &data.constraints);
467+
for arg in &data.args {
468+
match arg {
469+
AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
470+
AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
471+
}
472+
}
469473
}
470474
GenericArgs::Parenthesized(ref data) => {
471475
walk_list!(visitor, visit_ty, &data.inputs);

‎src/librustc_ast_lowering/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#![feature(crate_visibility_modifier)]
3535
#![feature(marker_trait_attr)]
3636
#![feature(specialization)]
37+
#![feature(or_patterns)]
3738
#![recursion_limit = "256"]
3839

3940
use rustc_ast::ast;

‎src/librustc_ast_lowering/path.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -366,22 +366,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
366366
param_mode: ParamMode,
367367
mut itctx: ImplTraitContext<'_, 'hir>,
368368
) -> (GenericArgsCtor<'hir>, bool) {
369-
let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
370-
let has_non_lt_args = args.iter().any(|arg| match arg {
371-
ast::GenericArg::Lifetime(_) => false,
372-
ast::GenericArg::Type(_) => true,
373-
ast::GenericArg::Const(_) => true,
369+
let has_non_lt_args = data.args.iter().any(|arg| match arg {
370+
AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
371+
| AngleBracketedArg::Constraint(_) => false,
372+
AngleBracketedArg::Arg(ast::GenericArg::Type(_) | ast::GenericArg::Const(_)) => true,
374373
});
375-
(
376-
GenericArgsCtor {
377-
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
378-
bindings: self.arena.alloc_from_iter(
379-
constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())),
380-
),
381-
parenthesized: false,
382-
},
383-
!has_non_lt_args && param_mode == ParamMode::Optional,
384-
)
374+
let args = data
375+
.args
376+
.iter()
377+
.filter_map(|arg| match arg {
378+
AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx.reborrow())),
379+
AngleBracketedArg::Constraint(_) => None,
380+
})
381+
.collect();
382+
let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
383+
AngleBracketedArg::Constraint(c) => {
384+
Some(self.lower_assoc_ty_constraint(c, itctx.reborrow()))
385+
}
386+
AngleBracketedArg::Arg(_) => None,
387+
}));
388+
let ctor = GenericArgsCtor { args, bindings, parenthesized: false };
389+
(ctor, !has_non_lt_args && param_mode == ParamMode::Optional)
385390
}
386391

387392
fn lower_parenthesized_parameter_data(

‎src/librustc_ast_passes/ast_validation.rs

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,34 @@ impl<'a> AstValidator<'a> {
639639
.emit();
640640
}
641641
}
642+
643+
/// Enforce generic args coming before constraints in `<...>` of a path segment.
644+
fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
645+
// Early exit in case it's partitioned as it should be.
646+
if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
647+
return;
648+
}
649+
// Find all generic argument coming after the first constraint...
650+
let mut misplaced_args = Vec::new();
651+
let mut first = None;
652+
for arg in &data.args {
653+
match (arg, first) {
654+
(AngleBracketedArg::Arg(a), Some(_)) => misplaced_args.push(a.span()),
655+
(AngleBracketedArg::Constraint(c), None) => first = Some(c.span),
656+
(AngleBracketedArg::Arg(_), None) | (AngleBracketedArg::Constraint(_), Some(_)) => {
657+
}
658+
}
659+
}
660+
// ...and then error:
661+
self.err_handler()
662+
.struct_span_err(
663+
misplaced_args.clone(),
664+
"generic arguments must come before the first constraint",
665+
)
666+
.span_label(first.unwrap(), "the first constraint is provided here")
667+
.span_labels(misplaced_args, "generic argument")
668+
.emit();
669+
}
642670
}
643671

644672
/// Checks that generic parameters are in the correct order,
@@ -1008,17 +1036,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10081036
fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
10091037
match *generic_args {
10101038
GenericArgs::AngleBracketed(ref data) => {
1011-
walk_list!(self, visit_generic_arg, &data.args);
1012-
1013-
// Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1014-
// are allowed to contain nested `impl Trait`.
1015-
self.with_impl_trait(None, |this| {
1016-
walk_list!(
1017-
this,
1018-
visit_assoc_ty_constraint_from_generic_args,
1019-
&data.constraints
1020-
);
1021-
});
1039+
self.check_generic_args_before_constraints(data);
1040+
1041+
for arg in &data.args {
1042+
match arg {
1043+
AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1044+
// Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1045+
// are allowed to contain nested `impl Trait`.
1046+
AngleBracketedArg::Constraint(constraint) => {
1047+
self.with_impl_trait(None, |this| {
1048+
this.visit_assoc_ty_constraint_from_generic_args(constraint);
1049+
});
1050+
}
1051+
}
1052+
}
10221053
}
10231054
GenericArgs::Parenthesized(ref data) => {
10241055
walk_list!(self, visit_ty, &data.inputs);

‎src/librustc_ast_passes/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
#![feature(bindings_after_at)]
21
//! The `rustc_ast_passes` crate contains passes which validate the AST in `syntax`
32
//! parsed by `rustc_parse` and then lowered, after the passes in this crate,
43
//! by `rustc_ast_lowering`.
54
//!
65
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
76
7+
#![feature(bindings_after_at)]
8+
#![feature(iter_is_partitioned)]
9+
810
pub mod ast_validation;
911
pub mod feature_gate;
1012
pub mod node_count;

‎src/librustc_ast_pretty/pprust.rs

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -796,31 +796,10 @@ impl<'a> PrintState<'a> for State<'a> {
796796
match *args {
797797
ast::GenericArgs::AngleBracketed(ref data) => {
798798
self.s.word("<");
799-
800-
self.commasep(Inconsistent, &data.args, |s, generic_arg| {
801-
s.print_generic_arg(generic_arg)
799+
self.commasep(Inconsistent, &data.args, |s, arg| match arg {
800+
ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
801+
ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
802802
});
803-
804-
let mut comma = !data.args.is_empty();
805-
806-
for constraint in data.constraints.iter() {
807-
if comma {
808-
self.word_space(",")
809-
}
810-
self.print_ident(constraint.ident);
811-
self.s.space();
812-
match constraint.kind {
813-
ast::AssocTyConstraintKind::Equality { ref ty } => {
814-
self.word_space("=");
815-
self.print_type(ty);
816-
}
817-
ast::AssocTyConstraintKind::Bound { ref bounds } => {
818-
self.print_type_bounds(":", &*bounds);
819-
}
820-
}
821-
comma = true;
822-
}
823-
824803
self.s.word(">")
825804
}
826805

@@ -891,6 +870,20 @@ impl<'a> State<'a> {
891870
}
892871
}
893872

873+
fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
874+
self.print_ident(constraint.ident);
875+
self.s.space();
876+
match &constraint.kind {
877+
ast::AssocTyConstraintKind::Equality { ty } => {
878+
self.word_space("=");
879+
self.print_type(ty);
880+
}
881+
ast::AssocTyConstraintKind::Bound { bounds } => {
882+
self.print_type_bounds(":", &*bounds);
883+
}
884+
}
885+
}
886+
894887
crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
895888
match generic_arg {
896889
GenericArg::Lifetime(lt) => self.print_lifetime(*lt),

‎src/librustc_expand/build.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ impl<'a> ExtCtxt<'a> {
3636
idents.into_iter().map(|ident| ast::PathSegment::from_ident(ident.with_span_pos(span))),
3737
);
3838
let args = if !args.is_empty() {
39-
ast::AngleBracketedArgs { args, constraints: Vec::new(), span }.into()
39+
let args = args.into_iter().map(ast::AngleBracketedArg::Arg).collect();
40+
ast::AngleBracketedArgs { args, span }.into()
4041
} else {
4142
None
4243
};

‎src/librustc_interface/util.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -634,17 +634,19 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
634634
match seg.args.as_ref().map(|generic_arg| &**generic_arg) {
635635
None => false,
636636
Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
637-
let types = data.args.iter().filter_map(|arg| match arg {
638-
ast::GenericArg::Type(ty) => Some(ty),
639-
_ => None,
640-
});
641-
any_involves_impl_trait(types)
642-
|| data.constraints.iter().any(|c| match c.kind {
637+
data.args.iter().any(|arg| match arg {
638+
ast::AngleBracketedArg::Arg(arg) => match arg {
639+
ast::GenericArg::Type(ty) => involves_impl_trait(ty),
640+
ast::GenericArg::Lifetime(_)
641+
| ast::GenericArg::Const(_) => false,
642+
},
643+
ast::AngleBracketedArg::Constraint(c) => match c.kind {
643644
ast::AssocTyConstraintKind::Bound { .. } => true,
644645
ast::AssocTyConstraintKind::Equality { ref ty } => {
645646
involves_impl_trait(ty)
646647
}
647-
})
648+
},
649+
})
648650
}
649651
Some(&ast::GenericArgs::Parenthesized(ref data)) => {
650652
any_involves_impl_trait(data.inputs.iter())

‎src/librustc_parse/parser/path.rs

Lines changed: 126 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use super::ty::{AllowPlus, RecoverQPath};
22
use super::{Parser, TokenType};
33
use crate::maybe_whole;
4-
use rustc_ast::ast::{
5-
self, AngleBracketedArgs, Ident, ParenthesizedArgs, Path, PathSegment, QSelf,
6-
};
7-
use rustc_ast::ast::{
8-
AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode, GenericArg,
9-
};
4+
use rustc_ast::ast::{self, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs};
5+
use rustc_ast::ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
6+
use rustc_ast::ast::{Ident, Path, PathSegment, QSelf};
7+
use rustc_ast::ptr::P;
108
use rustc_ast::token::{self, Token};
119
use rustc_errors::{pluralize, Applicability, PResult};
1210
use rustc_span::source_map::{BytePos, Span};
@@ -218,11 +216,11 @@ impl<'a> Parser<'a> {
218216
let lo = self.token.span;
219217
let args = if self.eat_lt() {
220218
// `<'a, T, A = U>`
221-
let (args, constraints) =
222-
self.parse_generic_args_with_leading_angle_bracket_recovery(style, lo)?;
219+
let args =
220+
self.parse_angle_args_with_leading_angle_bracket_recovery(style, lo)?;
223221
self.expect_gt()?;
224222
let span = lo.to(self.prev_token.span);
225-
AngleBracketedArgs { args, constraints, span }.into()
223+
AngleBracketedArgs { args, span }.into()
226224
} else {
227225
// `(T, U) -> R`
228226
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
@@ -251,18 +249,18 @@ impl<'a> Parser<'a> {
251249

252250
/// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
253251
/// For the purposes of understanding the parsing logic of generic arguments, this function
254-
/// can be thought of being the same as just calling `self.parse_generic_args()` if the source
252+
/// can be thought of being the same as just calling `self.parse_angle_args()` if the source
255253
/// had the correct amount of leading angle brackets.
256254
///
257255
/// ```ignore (diagnostics)
258256
/// bar::<<<<T as Foo>::Output>();
259257
/// ^^ help: remove extra angle brackets
260258
/// ```
261-
fn parse_generic_args_with_leading_angle_bracket_recovery(
259+
fn parse_angle_args_with_leading_angle_bracket_recovery(
262260
&mut self,
263261
style: PathStyle,
264262
lo: Span,
265-
) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
263+
) -> PResult<'a, Vec<AngleBracketedArg>> {
266264
// We need to detect whether there are extra leading left angle brackets and produce an
267265
// appropriate error and suggestion. This cannot be implemented by looking ahead at
268266
// upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
@@ -337,8 +335,8 @@ impl<'a> Parser<'a> {
337335
let snapshot = if is_first_invocation { Some(self.clone()) } else { None };
338336

339337
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
340-
match self.parse_generic_args() {
341-
Ok(value) => Ok(value),
338+
match self.parse_angle_args() {
339+
Ok(args) => Ok(args),
342340
Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
343341
// Cancel error from being unable to find `>`. We know the error
344342
// must have been this due to a non-zero unmatched angle bracket
@@ -381,110 +379,136 @@ impl<'a> Parser<'a> {
381379
.emit();
382380

383381
// Try again without unmatched angle bracket characters.
384-
self.parse_generic_args()
382+
self.parse_angle_args()
385383
}
386384
Err(e) => Err(e),
387385
}
388386
}
389387

390-
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
388+
/// Parses (possibly empty) list of generic arguments / associated item constraints,
391389
/// possibly including trailing comma.
392-
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
390+
fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
393391
let mut args = Vec::new();
394-
let mut constraints = Vec::new();
395-
let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
396-
let mut assoc_ty_constraints: Vec<Span> = Vec::new();
397-
398-
let args_lo = self.token.span;
399-
400-
loop {
401-
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
402-
// Parse lifetime argument.
403-
args.push(GenericArg::Lifetime(self.expect_lifetime()));
404-
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
405-
} else if self.check_ident()
406-
&& self.look_ahead(1, |t| t == &token::Eq || t == &token::Colon)
407-
{
408-
// Parse associated type constraint.
409-
let lo = self.token.span;
410-
let ident = self.parse_ident()?;
411-
let kind = if self.eat(&token::Eq) {
412-
AssocTyConstraintKind::Equality { ty: self.parse_ty()? }
413-
} else if self.eat(&token::Colon) {
414-
AssocTyConstraintKind::Bound {
415-
bounds: self.parse_generic_bounds(Some(self.prev_token.span))?,
416-
}
417-
} else {
418-
unreachable!();
419-
};
392+
while let Some(arg) = self.parse_angle_arg()? {
393+
args.push(arg);
394+
if !self.eat(&token::Comma) {
395+
break;
396+
}
397+
}
398+
Ok(args)
399+
}
420400

421-
let span = lo.to(self.prev_token.span);
401+
/// Parses a single argument in the angle arguments `<...>` of a path segment.
402+
fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
403+
if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon))
404+
{
405+
// Parse associated type constraint.
406+
let lo = self.token.span;
407+
let ident = self.parse_ident()?;
408+
let kind = if self.eat(&token::Eq) {
409+
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
410+
AssocTyConstraintKind::Equality { ty }
411+
} else if self.eat(&token::Colon) {
412+
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
413+
AssocTyConstraintKind::Bound { bounds }
414+
} else {
415+
unreachable!();
416+
};
422417

423-
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
424-
if let AssocTyConstraintKind::Bound { .. } = kind {
425-
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
426-
}
418+
let span = lo.to(self.prev_token.span);
427419

428-
constraints.push(AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span });
429-
assoc_ty_constraints.push(span);
430-
} else if self.check_const_arg() {
431-
// Parse const argument.
432-
let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
433-
self.parse_block_expr(
434-
None,
435-
self.token.span,
436-
BlockCheckMode::Default,
437-
ast::AttrVec::new(),
438-
)?
439-
} else if self.token.is_ident() {
440-
// FIXME(const_generics): to distinguish between idents for types and consts,
441-
// we should introduce a GenericArg::Ident in the AST and distinguish when
442-
// lowering to the HIR. For now, idents for const args are not permitted.
443-
if self.token.is_bool_lit() {
444-
self.parse_literal_maybe_minus()?
445-
} else {
446-
let span = self.token.span;
447-
let msg = "identifiers may currently not be used for const generics";
448-
self.struct_span_err(span, msg).emit();
449-
let block = self.mk_block_err(span);
450-
self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new())
451-
}
452-
} else {
453-
self.parse_literal_maybe_minus()?
454-
};
455-
let value = AnonConst { id: ast::DUMMY_NODE_ID, value: expr };
456-
args.push(GenericArg::Const(value));
457-
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
458-
} else if self.check_type() {
459-
// Parse type argument.
460-
args.push(GenericArg::Type(self.parse_ty()?));
461-
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
462-
} else {
463-
break;
420+
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
421+
if let AssocTyConstraintKind::Bound { .. } = kind {
422+
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
464423
}
465424

466-
if !self.eat(&token::Comma) {
467-
break;
468-
}
425+
let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span };
426+
Ok(Some(AngleBracketedArg::Constraint(constraint)))
427+
} else {
428+
Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg))
469429
}
430+
}
470431

471-
// FIXME: we would like to report this in ast_validation instead, but we currently do not
472-
// preserve ordering of generic parameters with respect to associated type binding, so we
473-
// lose that information after parsing.
474-
if !misplaced_assoc_ty_constraints.is_empty() {
475-
let mut err = self.struct_span_err(
476-
args_lo.to(self.prev_token.span),
477-
"associated type bindings must be declared after generic parameters",
478-
);
479-
for span in misplaced_assoc_ty_constraints {
480-
err.span_label(
481-
span,
482-
"this associated type binding should be moved after the generic parameters",
483-
);
432+
/// Parse the term to the right of an associated item equality constraint.
433+
/// That is, parse `<term>` in `Item = <term>`.
434+
/// Right now, this only admits types in `<term>`.
435+
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
436+
let arg = self.parse_generic_arg()?;
437+
let span = ident.span.to(self.prev_token.span);
438+
match arg {
439+
Some(GenericArg::Type(ty)) => return Ok(ty),
440+
Some(GenericArg::Const(expr)) => {
441+
self.struct_span_err(span, "cannot constrain an associated constant to a value")
442+
.span_label(ident.span, "this associated constant...")
443+
.span_label(expr.value.span, "...cannot be constrained to this value")
444+
.emit();
445+
}
446+
Some(GenericArg::Lifetime(lt)) => {
447+
self.struct_span_err(span, "associated lifetimes are not supported")
448+
.span_label(lt.ident.span, "the lifetime is given here")
449+
.help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
450+
.emit();
451+
}
452+
None => {
453+
let after_eq = eq.shrink_to_hi();
454+
let before_next = self.token.span.shrink_to_lo();
455+
self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`")
456+
.span_suggestion(
457+
self.sess.source_map().next_point(eq).to(before_next),
458+
"to constrain the associated type, add a type after `=`",
459+
" TheType".to_string(),
460+
Applicability::HasPlaceholders,
461+
)
462+
.span_suggestion(
463+
eq.to(before_next),
464+
&format!("remove the `=` if `{}` is a type", ident),
465+
String::new(),
466+
Applicability::MaybeIncorrect,
467+
)
468+
.emit();
484469
}
485-
err.emit();
486470
}
471+
Ok(self.mk_ty(span, ast::TyKind::Err))
472+
}
487473

488-
Ok((args, constraints))
474+
/// Parse a generic argument in a path segment.
475+
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
476+
fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
477+
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
478+
// Parse lifetime argument.
479+
GenericArg::Lifetime(self.expect_lifetime())
480+
} else if self.check_const_arg() {
481+
// Parse const argument.
482+
let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
483+
self.parse_block_expr(
484+
None,
485+
self.token.span,
486+
BlockCheckMode::Default,
487+
ast::AttrVec::new(),
488+
)?
489+
} else if self.token.is_ident() {
490+
// FIXME(const_generics): to distinguish between idents for types and consts,
491+
// we should introduce a GenericArg::Ident in the AST and distinguish when
492+
// lowering to the HIR. For now, idents for const args are not permitted.
493+
if self.token.is_bool_lit() {
494+
self.parse_literal_maybe_minus()?
495+
} else {
496+
let span = self.token.span;
497+
let msg = "identifiers may currently not be used for const generics";
498+
self.struct_span_err(span, msg).emit();
499+
let block = self.mk_block_err(span);
500+
self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new())
501+
}
502+
} else {
503+
self.parse_literal_maybe_minus()?
504+
};
505+
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr })
506+
} else if self.check_type() {
507+
// Parse type argument.
508+
GenericArg::Type(self.parse_ty()?)
509+
} else {
510+
return Ok(None);
511+
};
512+
Ok(Some(arg))
489513
}
490514
}

‎src/librustc_save_analysis/dump_visitor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
783783
match **generic_args {
784784
ast::GenericArgs::AngleBracketed(ref data) => {
785785
for arg in &data.args {
786-
if let ast::GenericArg::Type(ty) = arg {
786+
if let ast::AngleBracketedArg::Arg(ast::GenericArg::Type(ty)) = arg {
787787
self.visit_ty(ty);
788788
}
789789
}
@@ -849,7 +849,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
849849
if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
850850
for arg in &data.args {
851851
match arg {
852-
ast::GenericArg::Type(ty) => self.visit_ty(ty),
852+
ast::AngleBracketedArg::Arg(ast::GenericArg::Type(ty)) => self.visit_ty(ty),
853853
_ => {}
854854
}
855855
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// check-pass
2+
3+
#[cfg(FALSE)]
4+
fn syntax() {
5+
foo::<T = u8, T: Ord, String>();
6+
foo::<T = u8, 'a, T: Ord>();
7+
}
8+
9+
fn main() {}

‎src/test/ui/parser/issue-32214.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
trait Trait<T> { type Item; }
22

33
pub fn test<W, I: Trait<Item=(), W> >() {}
4-
//~^ ERROR associated type bindings must be declared after generic parameters
4+
//~^ ERROR generic arguments must come before the first constraint
55

66
fn main() { }

‎src/test/ui/parser/issue-32214.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: associated type bindings must be declared after generic parameters
2-
--> $DIR/issue-32214.rs:3:25
1+
error: generic arguments must come before the first constraint
2+
--> $DIR/issue-32214.rs:3:34
33
|
44
LL | pub fn test<W, I: Trait<Item=(), W> >() {}
5-
| -------^^^
5+
| ------- ^ generic argument
66
| |
7-
| this associated type binding should be moved after the generic parameters
7+
| the first constraint is provided here
88

99
error: aborting due to previous error
1010

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#[cfg(FALSE)]
2+
fn syntax() {
3+
bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
4+
bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value
5+
}
6+
7+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: cannot constrain an associated constant to a value
2+
--> $DIR/recover-assoc-const-constraint.rs:3:11
3+
|
4+
LL | bar::<Item = 42>();
5+
| ----^^^--
6+
| | |
7+
| | ...cannot be constrained to this value
8+
| this associated constant...
9+
10+
error: cannot constrain an associated constant to a value
11+
--> $DIR/recover-assoc-const-constraint.rs:4:11
12+
|
13+
LL | bar::<Item = { 42 }>();
14+
| ----^^^------
15+
| | |
16+
| | ...cannot be constrained to this value
17+
| this associated constant...
18+
19+
error: aborting due to 2 previous errors
20+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[cfg(FALSE)]
2+
fn syntax() {
3+
bar::<Item = >(); //~ ERROR missing type to the right of `=`
4+
}
5+
6+
fn main() {}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: missing type to the right of `=`
2+
--> $DIR/recover-assoc-eq-missing-term.rs:3:17
3+
|
4+
LL | bar::<Item = >();
5+
| ^^^
6+
|
7+
help: to constrain the associated type, add a type after `=`
8+
|
9+
LL | bar::<Item = TheType>();
10+
| ^^^^^^^
11+
help: remove the `=` if `Item` is a type
12+
|
13+
LL | bar::<Item >();
14+
| --
15+
16+
error: aborting due to previous error
17+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[cfg(FALSE)]
2+
fn syntax() {
3+
bar::<Item = 'a>(); //~ ERROR associated lifetimes are not supported
4+
}
5+
6+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: associated lifetimes are not supported
2+
--> $DIR/recover-assoc-lifetime-constraint.rs:3:11
3+
|
4+
LL | bar::<Item = 'a>();
5+
| ^^^^^^^--
6+
| |
7+
| the lifetime is given here
8+
|
9+
= help: if you meant to specify a trait object, write `dyn Trait + 'lifetime`
10+
11+
error: aborting due to previous error
12+

‎src/test/ui/suggestions/suggest-move-types.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// ignore-tidy-linelength
2-
31
#![allow(warnings)]
42

53
// This test verifies that the suggestion to move types before associated type bindings
@@ -25,60 +23,64 @@ trait ThreeWithLifetime<'a, 'b, 'c, T, U, V> {
2523
type C;
2624
}
2725

28-
struct A<T, M: One<A=(), T>> { //~ ERROR associated type bindings must be declared after generic parameters
26+
struct A<T, M: One<A=(), T>> {
27+
//~^ ERROR generic arguments must come before the first constraint
2928
m: M,
3029
t: T,
3130
}
3231

3332

3433
struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
35-
//~^ ERROR associated type bindings must be declared after generic parameters
34+
//~^ ERROR generic arguments must come before the first constraint
3635
//~^^ ERROR type provided when a lifetime was expected
3736
m: M,
3837
t: &'a T,
3938
}
4039

41-
struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR associated type bindings must be declared after generic parameters
40+
struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> {
41+
//~^ ERROR generic arguments must come before the first constraint
4242
m: M,
4343
t: T,
4444
u: U,
4545
v: V,
4646
}
4747

4848
struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
49-
//~^ ERROR associated type bindings must be declared after generic parameters
49+
//~^ ERROR generic arguments must come before the first constraint
5050
//~^^ ERROR type provided when a lifetime was expected
5151
m: M,
5252
t: &'a T,
5353
u: &'b U,
5454
v: &'c V,
5555
}
5656

57-
struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR associated type bindings must be declared after generic parameters
57+
struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> {
58+
//~^ ERROR generic arguments must come before the first constraint
5859
m: M,
5960
t: T,
6061
u: U,
6162
v: V,
6263
}
6364

6465
struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
65-
//~^ ERROR associated type bindings must be declared after generic parameters
66+
//~^ ERROR generic arguments must come before the first constraint
6667
//~^^ ERROR lifetime provided when a type was expected
6768
m: M,
6869
t: &'a T,
6970
u: &'b U,
7071
v: &'c V,
7172
}
7273

73-
struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR associated type bindings must be declared after generic parameters
74+
struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> {
75+
//~^ ERROR generic arguments must come before the first constraint
7476
m: M,
7577
t: T,
7678
u: U,
7779
v: V,
7880
}
7981

8082
struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
81-
//~^ ERROR associated type bindings must be declared after generic parameters
83+
//~^ ERROR generic arguments must come before the first constraint
8284
//~^^ ERROR lifetime provided when a type was expected
8385
m: M,
8486
t: &'a T,

‎src/test/ui/suggestions/suggest-move-types.stderr

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,85 @@
1-
error: associated type bindings must be declared after generic parameters
2-
--> $DIR/suggest-move-types.rs:28:20
1+
error: generic arguments must come before the first constraint
2+
--> $DIR/suggest-move-types.rs:26:26
33
|
44
LL | struct A<T, M: One<A=(), T>> {
5-
| ----^^^
5+
| ---- ^ generic argument
66
| |
7-
| this associated type binding should be moved after the generic parameters
7+
| the first constraint is provided here
88

9-
error: associated type bindings must be declared after generic parameters
10-
--> $DIR/suggest-move-types.rs:34:37
9+
error: generic arguments must come before the first constraint
10+
--> $DIR/suggest-move-types.rs:33:43
1111
|
1212
LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
13-
| ----^^^^^^^
14-
| |
15-
| this associated type binding should be moved after the generic parameters
13+
| ---- ^ ^^ generic argument
14+
| | |
15+
| | generic argument
16+
| the first constraint is provided here
1617

17-
error: associated type bindings must be declared after generic parameters
18-
--> $DIR/suggest-move-types.rs:41:28
18+
error: generic arguments must come before the first constraint
19+
--> $DIR/suggest-move-types.rs:40:46
1920
|
2021
LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> {
21-
| ----^^----^^----^^^^^^^^^
22-
| | | |
23-
| | | this associated type binding should be moved after the generic parameters
24-
| | this associated type binding should be moved after the generic parameters
25-
| this associated type binding should be moved after the generic parameters
22+
| ---- ^ ^ ^ generic argument
23+
| | | |
24+
| | | generic argument
25+
| | generic argument
26+
| the first constraint is provided here
2627

27-
error: associated type bindings must be declared after generic parameters
28-
--> $DIR/suggest-move-types.rs:48:53
28+
error: generic arguments must come before the first constraint
29+
--> $DIR/suggest-move-types.rs:48:71
2930
|
3031
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
31-
| ----^^----^^----^^^^^^^^^^^^^^^^^^^^^
32-
| | | |
33-
| | | this associated type binding should be moved after the generic parameters
34-
| | this associated type binding should be moved after the generic parameters
35-
| this associated type binding should be moved after the generic parameters
32+
| ---- ^ ^ ^ ^^ ^^ ^^ generic argument
33+
| | | | | | |
34+
| | | | | | generic argument
35+
| | | | | generic argument
36+
| | | | generic argument
37+
| | | generic argument
38+
| | generic argument
39+
| the first constraint is provided here
3640

37-
error: associated type bindings must be declared after generic parameters
38-
--> $DIR/suggest-move-types.rs:57:28
41+
error: generic arguments must come before the first constraint
42+
--> $DIR/suggest-move-types.rs:57:49
3943
|
4044
LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> {
41-
| ^^^----^^----^^----^^^^^^
42-
| | | |
43-
| | | this associated type binding should be moved after the generic parameters
44-
| | this associated type binding should be moved after the generic parameters
45-
| this associated type binding should be moved after the generic parameters
45+
| ---- ^ ^ generic argument
46+
| | |
47+
| | generic argument
48+
| the first constraint is provided here
4649

47-
error: associated type bindings must be declared after generic parameters
48-
--> $DIR/suggest-move-types.rs:64:53
50+
error: generic arguments must come before the first constraint
51+
--> $DIR/suggest-move-types.rs:65:78
4952
|
5053
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
51-
| ^^^^^^^----^^----^^----^^^^^^^^^^^^^^
52-
| | | |
53-
| | | this associated type binding should be moved after the generic parameters
54-
| | this associated type binding should be moved after the generic parameters
55-
| this associated type binding should be moved after the generic parameters
54+
| ---- ^ ^^ ^ ^^ generic argument
55+
| | | | |
56+
| | | | generic argument
57+
| | | generic argument
58+
| | generic argument
59+
| the first constraint is provided here
5660

57-
error: associated type bindings must be declared after generic parameters
58-
--> $DIR/suggest-move-types.rs:73:28
61+
error: generic arguments must come before the first constraint
62+
--> $DIR/suggest-move-types.rs:74:43
5963
|
6064
LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> {
61-
| ^^^----^^----^^^^^----^^^
62-
| | | |
63-
| | | this associated type binding should be moved after the generic parameters
64-
| | this associated type binding should be moved after the generic parameters
65-
| this associated type binding should be moved after the generic parameters
65+
| ---- ^ ^ generic argument
66+
| | |
67+
| | generic argument
68+
| the first constraint is provided here
6669

67-
error: associated type bindings must be declared after generic parameters
68-
--> $DIR/suggest-move-types.rs:80:53
70+
error: generic arguments must come before the first constraint
71+
--> $DIR/suggest-move-types.rs:82:72
6972
|
7073
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
71-
| ^^^^^^^----^^----^^^^^^^^^----^^^^^^^
72-
| | | |
73-
| | | this associated type binding should be moved after the generic parameters
74-
| | this associated type binding should be moved after the generic parameters
75-
| this associated type binding should be moved after the generic parameters
74+
| ---- ^ ^^ ^ ^^ generic argument
75+
| | | | |
76+
| | | | generic argument
77+
| | | generic argument
78+
| | generic argument
79+
| the first constraint is provided here
7680

7781
error[E0747]: type provided when a lifetime was expected
78-
--> $DIR/suggest-move-types.rs:34:43
82+
--> $DIR/suggest-move-types.rs:33:43
7983
|
8084
LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
8185
| ^
@@ -91,15 +95,15 @@ LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U,
9195
= note: lifetime arguments must be provided before type arguments
9296

9397
error[E0747]: lifetime provided when a type was expected
94-
--> $DIR/suggest-move-types.rs:64:56
98+
--> $DIR/suggest-move-types.rs:65:56
9599
|
96100
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
97101
| ^^
98102
|
99103
= note: type arguments must be provided before lifetime arguments
100104

101105
error[E0747]: lifetime provided when a type was expected
102-
--> $DIR/suggest-move-types.rs:80:56
106+
--> $DIR/suggest-move-types.rs:82:56
103107
|
104108
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
105109
| ^^

0 commit comments

Comments
 (0)
Please sign in to comment.