Skip to content

Commit b9d5ee5

Browse files
committed
Auto merge of rust-lang#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 rust-lang#70256. r? @varkor
2 parents b76238a + 42c5cfd commit b9d5ee5

23 files changed

+404
-247
lines changed

src/librustc_ast/ast.rs

+19-10
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

+5-3
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

+6-2
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

+1
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

+20-15
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

+42-11
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

+3-1
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

+17-24
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

+2-1
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

+9-7
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())

0 commit comments

Comments
 (0)