未验证 提交 b6fb582c 编写于 作者: Y Yuki Okushi 提交者: GitHub

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 `:`
```
...@@ -814,7 +814,7 @@ fn ty_to_string(&self, ty: &ast::Ty) -> String { ...@@ -814,7 +814,7 @@ fn ty_to_string(&self, ty: &ast::Ty) -> String {
} }
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 @@ pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) { ...@@ -991,7 +991,12 @@ pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
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 @@ pub fn print_type(&mut self, ty: &ast::Ty) { ...@@ -1045,11 +1050,14 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
} }
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,29 +1557,24 @@ pub(crate) fn print_asyncness(&mut self, asyncness: ast::Async) { ...@@ -1549,29 +1557,24 @@ pub(crate) fn print_asyncness(&mut self, asyncness: ast::Async) {
} }
} }
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() { let mut first = true;
self.word(prefix); for bound in bounds {
let mut first = true; if first {
for bound in bounds { first = false;
if !(first && prefix.is_empty()) { } else {
self.nbsp(); self.nbsp();
} self.word_space("+");
if first { }
first = false;
} else {
self.word_space("+");
}
match bound { match bound {
GenericBound::Trait(tref, modifier) => { GenericBound::Trait(tref, modifier) => {
if modifier == &TraitBoundModifier::Maybe { if modifier == &TraitBoundModifier::Maybe {
self.word("?"); self.word("?");
}
self.print_poly_trait_ref(tref);
} }
GenericBound::Outlives(lt) => self.print_lifetime(*lt), self.print_poly_trait_ref(tref);
} }
GenericBound::Outlives(lt) => self.print_lifetime(*lt),
} }
} }
} }
...@@ -1580,22 +1583,14 @@ pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) { ...@@ -1580,22 +1583,14 @@ 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, for (i, bound) in bounds.iter().enumerate() {
lifetime: ast::Lifetime, if i != 0 {
bounds: &ast::GenericBounds, self.word(" + ");
) { }
self.print_lifetime(lifetime); match bound {
if !bounds.is_empty() { ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
self.word(": "); _ => panic!(),
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
self.word(" + ");
}
match bound {
ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
_ => panic!(),
}
} }
} }
} }
...@@ -1613,11 +1608,18 @@ pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericPara ...@@ -1613,11 +1608,18 @@ pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericPara
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, &param.bounds) s.print_lifetime(lt);
if !param.bounds.is_empty() {
s.word_nbsp(":");
s.print_lifetime_bounds(&param.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(":", &param.bounds); if !param.bounds.is_empty() {
s.word_nbsp(":");
s.print_type_bounds(&param.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 @@ pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericPara ...@@ -1630,7 +1632,10 @@ pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericPara
s.space(); s.space();
s.word_space(":"); s.word_space(":");
s.print_type(ty); s.print_type(ty);
s.print_type_bounds(":", &param.bounds); if !param.bounds.is_empty() {
s.word_nbsp(":");
s.print_type_bounds(&param.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 @@ fn print_associated_type( ...@@ -114,7 +114,10 @@ fn print_associated_type(
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 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) { ...@@ -320,7 +323,10 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
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 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) { ...@@ -347,7 +353,10 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
} }
} }
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 @@ pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { ...@@ -618,14 +627,23 @@ pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
}) => { }) => {
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 @@ pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a ...@@ -1355,7 +1355,10 @@ pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'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 @@ ...@@ -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() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册