Skip to content

Commit b6fb582

Browse files
authored
Rollup merge of #98183 - dtolnay:emptybound, r=lcnr
Fix pretty printing of empty bound lists in where-clause Repro: ```rust macro_rules! assert_item_stringify { ($item:item $expected:literal) => { assert_eq!(stringify!($item), $expected); }; } fn main() { assert_item_stringify! { fn f<'a, T>() where 'a:, T: {} "fn f<'a, T>() where 'a:, T: {}" } } ``` Previously this assertion would fail because rustc renders the where-clause as `where 'a, T` which is invalid syntax. This PR makes the above assertion pass. This bug also affects `-Zunpretty=expanded`. The intention is for that to emit syntactically valid code, but the buggy output is not valid Rust syntax. ```console $ rustc <(echo "fn f<'a, T>() where 'a:, T: {}") -Zunpretty=expanded #![feature(prelude_import)] #![no_std] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; fn f<'a, T>() where 'a, T {} ``` ```console $ rustc <(echo "fn f<'a, T>() where 'a:, T: {}") -Zunpretty=expanded | rustc - error: expected `:`, found `,` --> <anon>:7:23 | 7 | fn f<'a, T>() where 'a, T {} | ^ expected `:` ```
2 parents 9a0b774 + fe9635f commit b6fb582

File tree

4 files changed

+79
-50
lines changed

4 files changed

+79
-50
lines changed

compiler/rustc_ast_pretty/src/pprust/state.rs

+49-44
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
814814
}
815815

816816
fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
817-
Self::to_string(|s| s.print_type_bounds("", bounds))
817+
Self::to_string(|s| s.print_type_bounds(bounds))
818818
}
819819

820820
fn pat_to_string(&self, pat: &ast::Pat) -> String {
@@ -991,7 +991,12 @@ impl<'a> State<'a> {
991991
Term::Const(c) => self.print_expr_anon_const(c, &[]),
992992
}
993993
}
994-
ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
994+
ast::AssocConstraintKind::Bound { bounds } => {
995+
if !bounds.is_empty() {
996+
self.word_nbsp(":");
997+
self.print_type_bounds(&bounds);
998+
}
999+
}
9951000
}
9961001
}
9971002

@@ -1045,11 +1050,14 @@ impl<'a> State<'a> {
10451050
}
10461051
ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
10471052
ast::TyKind::TraitObject(ref bounds, syntax) => {
1048-
let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
1049-
self.print_type_bounds(prefix, &bounds);
1053+
if syntax == ast::TraitObjectSyntax::Dyn {
1054+
self.word_nbsp("dyn");
1055+
}
1056+
self.print_type_bounds(bounds);
10501057
}
10511058
ast::TyKind::ImplTrait(_, ref bounds) => {
1052-
self.print_type_bounds("impl", &bounds);
1059+
self.word_nbsp("impl");
1060+
self.print_type_bounds(bounds);
10531061
}
10541062
ast::TyKind::Array(ref ty, ref length) => {
10551063
self.word("[");
@@ -1549,29 +1557,24 @@ impl<'a> State<'a> {
15491557
}
15501558
}
15511559

1552-
pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
1553-
if !bounds.is_empty() {
1554-
self.word(prefix);
1555-
let mut first = true;
1556-
for bound in bounds {
1557-
if !(first && prefix.is_empty()) {
1558-
self.nbsp();
1559-
}
1560-
if first {
1561-
first = false;
1562-
} else {
1563-
self.word_space("+");
1564-
}
1560+
pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
1561+
let mut first = true;
1562+
for bound in bounds {
1563+
if first {
1564+
first = false;
1565+
} else {
1566+
self.nbsp();
1567+
self.word_space("+");
1568+
}
15651569

1566-
match bound {
1567-
GenericBound::Trait(tref, modifier) => {
1568-
if modifier == &TraitBoundModifier::Maybe {
1569-
self.word("?");
1570-
}
1571-
self.print_poly_trait_ref(tref);
1570+
match bound {
1571+
GenericBound::Trait(tref, modifier) => {
1572+
if modifier == &TraitBoundModifier::Maybe {
1573+
self.word("?");
15721574
}
1573-
GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1575+
self.print_poly_trait_ref(tref);
15741576
}
1577+
GenericBound::Outlives(lt) => self.print_lifetime(*lt),
15751578
}
15761579
}
15771580
}
@@ -1580,22 +1583,14 @@ impl<'a> State<'a> {
15801583
self.print_name(lifetime.ident.name)
15811584
}
15821585

1583-
pub(crate) fn print_lifetime_bounds(
1584-
&mut self,
1585-
lifetime: ast::Lifetime,
1586-
bounds: &ast::GenericBounds,
1587-
) {
1588-
self.print_lifetime(lifetime);
1589-
if !bounds.is_empty() {
1590-
self.word(": ");
1591-
for (i, bound) in bounds.iter().enumerate() {
1592-
if i != 0 {
1593-
self.word(" + ");
1594-
}
1595-
match bound {
1596-
ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1597-
_ => panic!(),
1598-
}
1586+
pub(crate) fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
1587+
for (i, bound) in bounds.iter().enumerate() {
1588+
if i != 0 {
1589+
self.word(" + ");
1590+
}
1591+
match bound {
1592+
ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1593+
_ => panic!(),
15991594
}
16001595
}
16011596
}
@@ -1613,11 +1608,18 @@ impl<'a> State<'a> {
16131608
match param.kind {
16141609
ast::GenericParamKind::Lifetime => {
16151610
let lt = ast::Lifetime { id: param.id, ident: param.ident };
1616-
s.print_lifetime_bounds(lt, &param.bounds)
1611+
s.print_lifetime(lt);
1612+
if !param.bounds.is_empty() {
1613+
s.word_nbsp(":");
1614+
s.print_lifetime_bounds(&param.bounds)
1615+
}
16171616
}
16181617
ast::GenericParamKind::Type { ref default } => {
16191618
s.print_ident(param.ident);
1620-
s.print_type_bounds(":", &param.bounds);
1619+
if !param.bounds.is_empty() {
1620+
s.word_nbsp(":");
1621+
s.print_type_bounds(&param.bounds);
1622+
}
16211623
if let Some(ref default) = default {
16221624
s.space();
16231625
s.word_space("=");
@@ -1630,7 +1632,10 @@ impl<'a> State<'a> {
16301632
s.space();
16311633
s.word_space(":");
16321634
s.print_type(ty);
1633-
s.print_type_bounds(":", &param.bounds);
1635+
if !param.bounds.is_empty() {
1636+
s.word_nbsp(":");
1637+
s.print_type_bounds(&param.bounds);
1638+
}
16341639
if let Some(ref default) = default {
16351640
s.space();
16361641
s.word_space("=");

compiler/rustc_ast_pretty/src/pprust/state/item.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,10 @@ impl<'a> State<'a> {
114114
self.word_space("type");
115115
self.print_ident(ident);
116116
self.print_generic_params(&generics.params);
117-
self.print_type_bounds(":", bounds);
117+
if !bounds.is_empty() {
118+
self.word_nbsp(":");
119+
self.print_type_bounds(bounds);
120+
}
118121
self.print_where_clause_parts(where_clauses.0.0, before_predicates);
119122
if let Some(ty) = ty {
120123
self.space();
@@ -320,7 +323,10 @@ impl<'a> State<'a> {
320323
real_bounds.push(b.clone());
321324
}
322325
}
323-
self.print_type_bounds(":", &real_bounds);
326+
if !real_bounds.is_empty() {
327+
self.word_nbsp(":");
328+
self.print_type_bounds(&real_bounds);
329+
}
324330
self.print_where_clause(&generics.where_clause);
325331
self.word(" ");
326332
self.bopen();
@@ -347,7 +353,10 @@ impl<'a> State<'a> {
347353
}
348354
}
349355
self.nbsp();
350-
self.print_type_bounds("=", &real_bounds);
356+
if !real_bounds.is_empty() {
357+
self.word_nbsp("=");
358+
self.print_type_bounds(&real_bounds);
359+
}
351360
self.print_where_clause(&generics.where_clause);
352361
self.word(";");
353362
self.end(); // end inner head-block
@@ -618,14 +627,23 @@ impl<'a> State<'a> {
618627
}) => {
619628
self.print_formal_generic_params(bound_generic_params);
620629
self.print_type(bounded_ty);
621-
self.print_type_bounds(":", bounds);
630+
self.word(":");
631+
if !bounds.is_empty() {
632+
self.nbsp();
633+
self.print_type_bounds(bounds);
634+
}
622635
}
623636
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
624637
lifetime,
625638
bounds,
626639
..
627640
}) => {
628-
self.print_lifetime_bounds(*lifetime, bounds);
641+
self.print_lifetime(*lifetime);
642+
self.word(":");
643+
if !bounds.is_empty() {
644+
self.nbsp();
645+
self.print_lifetime_bounds(bounds);
646+
}
629647
}
630648
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
631649
self.print_type(lhs_ty);

compiler/rustc_parse/src/parser/diagnostics.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,10 @@ impl<'a> Parser<'a> {
13551355
s.print_mutability(mut_ty.mutbl, false);
13561356
s.popen();
13571357
s.print_type(&mut_ty.ty);
1358-
s.print_type_bounds(" +", &bounds);
1358+
if !bounds.is_empty() {
1359+
s.word(" + ");
1360+
s.print_type_bounds(&bounds);
1361+
}
13591362
s.pclose()
13601363
});
13611364

src/test/pretty/where-clauses.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22

33
fn f<'a, 'b, T>(t: T) -> isize where T: 'a, 'a: 'b, T: Eq { 0 }
44

5+
// This is legal syntax, sometimes generated by macros. `where T: $($bound+)*`
6+
fn zero_bounds<'a, T>() where 'a:, T: {}
7+
58
fn main() {}

0 commit comments

Comments
 (0)