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 `:` ```
This commit is contained in:
commit
b6fb582cb7
4 changed files with 79 additions and 50 deletions
|
@ -814,7 +814,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
|
fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
|
||||||
Self::to_string(|s| s.print_type_bounds("", bounds))
|
Self::to_string(|s| s.print_type_bounds(bounds))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_to_string(&self, pat: &ast::Pat) -> String {
|
fn pat_to_string(&self, pat: &ast::Pat) -> String {
|
||||||
|
@ -991,7 +991,12 @@ impl<'a> State<'a> {
|
||||||
Term::Const(c) => self.print_expr_anon_const(c, &[]),
|
Term::Const(c) => self.print_expr_anon_const(c, &[]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
|
ast::AssocConstraintKind::Bound { bounds } => {
|
||||||
|
if !bounds.is_empty() {
|
||||||
|
self.word_nbsp(":");
|
||||||
|
self.print_type_bounds(&bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1045,11 +1050,14 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
|
ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
|
||||||
ast::TyKind::TraitObject(ref bounds, syntax) => {
|
ast::TyKind::TraitObject(ref bounds, syntax) => {
|
||||||
let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
|
if syntax == ast::TraitObjectSyntax::Dyn {
|
||||||
self.print_type_bounds(prefix, &bounds);
|
self.word_nbsp("dyn");
|
||||||
|
}
|
||||||
|
self.print_type_bounds(bounds);
|
||||||
}
|
}
|
||||||
ast::TyKind::ImplTrait(_, ref bounds) => {
|
ast::TyKind::ImplTrait(_, ref bounds) => {
|
||||||
self.print_type_bounds("impl", &bounds);
|
self.word_nbsp("impl");
|
||||||
|
self.print_type_bounds(bounds);
|
||||||
}
|
}
|
||||||
ast::TyKind::Array(ref ty, ref length) => {
|
ast::TyKind::Array(ref ty, ref length) => {
|
||||||
self.word("[");
|
self.word("[");
|
||||||
|
@ -1549,17 +1557,13 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
|
pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
|
||||||
if !bounds.is_empty() {
|
|
||||||
self.word(prefix);
|
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for bound in bounds {
|
for bound in bounds {
|
||||||
if !(first && prefix.is_empty()) {
|
|
||||||
self.nbsp();
|
|
||||||
}
|
|
||||||
if first {
|
if first {
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
|
self.nbsp();
|
||||||
self.word_space("+");
|
self.word_space("+");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1574,20 +1578,12 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
|
pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
|
||||||
self.print_name(lifetime.ident.name)
|
self.print_name(lifetime.ident.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_lifetime_bounds(
|
pub(crate) fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
|
||||||
&mut self,
|
|
||||||
lifetime: ast::Lifetime,
|
|
||||||
bounds: &ast::GenericBounds,
|
|
||||||
) {
|
|
||||||
self.print_lifetime(lifetime);
|
|
||||||
if !bounds.is_empty() {
|
|
||||||
self.word(": ");
|
|
||||||
for (i, bound) in bounds.iter().enumerate() {
|
for (i, bound) in bounds.iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
self.word(" + ");
|
self.word(" + ");
|
||||||
|
@ -1598,7 +1594,6 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
|
pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
|
||||||
if generic_params.is_empty() {
|
if generic_params.is_empty() {
|
||||||
|
@ -1613,11 +1608,18 @@ impl<'a> State<'a> {
|
||||||
match param.kind {
|
match param.kind {
|
||||||
ast::GenericParamKind::Lifetime => {
|
ast::GenericParamKind::Lifetime => {
|
||||||
let lt = ast::Lifetime { id: param.id, ident: param.ident };
|
let lt = ast::Lifetime { id: param.id, ident: param.ident };
|
||||||
s.print_lifetime_bounds(lt, ¶m.bounds)
|
s.print_lifetime(lt);
|
||||||
|
if !param.bounds.is_empty() {
|
||||||
|
s.word_nbsp(":");
|
||||||
|
s.print_lifetime_bounds(¶m.bounds)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast::GenericParamKind::Type { ref default } => {
|
ast::GenericParamKind::Type { ref default } => {
|
||||||
s.print_ident(param.ident);
|
s.print_ident(param.ident);
|
||||||
s.print_type_bounds(":", ¶m.bounds);
|
if !param.bounds.is_empty() {
|
||||||
|
s.word_nbsp(":");
|
||||||
|
s.print_type_bounds(¶m.bounds);
|
||||||
|
}
|
||||||
if let Some(ref default) = default {
|
if let Some(ref default) = default {
|
||||||
s.space();
|
s.space();
|
||||||
s.word_space("=");
|
s.word_space("=");
|
||||||
|
@ -1630,7 +1632,10 @@ impl<'a> State<'a> {
|
||||||
s.space();
|
s.space();
|
||||||
s.word_space(":");
|
s.word_space(":");
|
||||||
s.print_type(ty);
|
s.print_type(ty);
|
||||||
s.print_type_bounds(":", ¶m.bounds);
|
if !param.bounds.is_empty() {
|
||||||
|
s.word_nbsp(":");
|
||||||
|
s.print_type_bounds(¶m.bounds);
|
||||||
|
}
|
||||||
if let Some(ref default) = default {
|
if let Some(ref default) = default {
|
||||||
s.space();
|
s.space();
|
||||||
s.word_space("=");
|
s.word_space("=");
|
||||||
|
|
|
@ -114,7 +114,10 @@ impl<'a> State<'a> {
|
||||||
self.word_space("type");
|
self.word_space("type");
|
||||||
self.print_ident(ident);
|
self.print_ident(ident);
|
||||||
self.print_generic_params(&generics.params);
|
self.print_generic_params(&generics.params);
|
||||||
self.print_type_bounds(":", bounds);
|
if !bounds.is_empty() {
|
||||||
|
self.word_nbsp(":");
|
||||||
|
self.print_type_bounds(bounds);
|
||||||
|
}
|
||||||
self.print_where_clause_parts(where_clauses.0.0, before_predicates);
|
self.print_where_clause_parts(where_clauses.0.0, before_predicates);
|
||||||
if let Some(ty) = ty {
|
if let Some(ty) = ty {
|
||||||
self.space();
|
self.space();
|
||||||
|
@ -320,7 +323,10 @@ impl<'a> State<'a> {
|
||||||
real_bounds.push(b.clone());
|
real_bounds.push(b.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.print_type_bounds(":", &real_bounds);
|
if !real_bounds.is_empty() {
|
||||||
|
self.word_nbsp(":");
|
||||||
|
self.print_type_bounds(&real_bounds);
|
||||||
|
}
|
||||||
self.print_where_clause(&generics.where_clause);
|
self.print_where_clause(&generics.where_clause);
|
||||||
self.word(" ");
|
self.word(" ");
|
||||||
self.bopen();
|
self.bopen();
|
||||||
|
@ -347,7 +353,10 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.nbsp();
|
self.nbsp();
|
||||||
self.print_type_bounds("=", &real_bounds);
|
if !real_bounds.is_empty() {
|
||||||
|
self.word_nbsp("=");
|
||||||
|
self.print_type_bounds(&real_bounds);
|
||||||
|
}
|
||||||
self.print_where_clause(&generics.where_clause);
|
self.print_where_clause(&generics.where_clause);
|
||||||
self.word(";");
|
self.word(";");
|
||||||
self.end(); // end inner head-block
|
self.end(); // end inner head-block
|
||||||
|
@ -618,14 +627,23 @@ impl<'a> State<'a> {
|
||||||
}) => {
|
}) => {
|
||||||
self.print_formal_generic_params(bound_generic_params);
|
self.print_formal_generic_params(bound_generic_params);
|
||||||
self.print_type(bounded_ty);
|
self.print_type(bounded_ty);
|
||||||
self.print_type_bounds(":", bounds);
|
self.word(":");
|
||||||
|
if !bounds.is_empty() {
|
||||||
|
self.nbsp();
|
||||||
|
self.print_type_bounds(bounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
||||||
lifetime,
|
lifetime,
|
||||||
bounds,
|
bounds,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
self.print_lifetime_bounds(*lifetime, bounds);
|
self.print_lifetime(*lifetime);
|
||||||
|
self.word(":");
|
||||||
|
if !bounds.is_empty() {
|
||||||
|
self.nbsp();
|
||||||
|
self.print_lifetime_bounds(bounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
|
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
|
||||||
self.print_type(lhs_ty);
|
self.print_type(lhs_ty);
|
||||||
|
|
|
@ -1355,7 +1355,10 @@ impl<'a> Parser<'a> {
|
||||||
s.print_mutability(mut_ty.mutbl, false);
|
s.print_mutability(mut_ty.mutbl, false);
|
||||||
s.popen();
|
s.popen();
|
||||||
s.print_type(&mut_ty.ty);
|
s.print_type(&mut_ty.ty);
|
||||||
s.print_type_bounds(" +", &bounds);
|
if !bounds.is_empty() {
|
||||||
|
s.word(" + ");
|
||||||
|
s.print_type_bounds(&bounds);
|
||||||
|
}
|
||||||
s.pclose()
|
s.pclose()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,4 +2,7 @@
|
||||||
|
|
||||||
fn f<'a, 'b, T>(t: T) -> isize where T: 'a, 'a: 'b, T: Eq { 0 }
|
fn f<'a, 'b, T>(t: T) -> isize where T: 'a, 'a: 'b, T: Eq { 0 }
|
||||||
|
|
||||||
|
// This is legal syntax, sometimes generated by macros. `where T: $($bound+)*`
|
||||||
|
fn zero_bounds<'a, T>() where 'a:, T: {}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
Loading…
Add table
Reference in a new issue