diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b80a553b4185ce7f3b551b66c299470c15e83146..ad8dbfd506d212f32d9931d945995a597f0e515d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -814,7 +814,7 @@ fn ty_to_string(&self, ty: &ast::Ty) -> 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 { @@ -991,7 +991,12 @@ pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) { 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) { } ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false), ast::TyKind::TraitObject(ref bounds, syntax) => { - let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" }; - self.print_type_bounds(prefix, &bounds); + if syntax == ast::TraitObjectSyntax::Dyn { + self.word_nbsp("dyn"); + } + self.print_type_bounds(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) => { self.word("["); @@ -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]) { - if !bounds.is_empty() { - self.word(prefix); - let mut first = true; - for bound in bounds { - if !(first && prefix.is_empty()) { - self.nbsp(); - } - if first { - first = false; - } else { - self.word_space("+"); - } + pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) { + let mut first = true; + for bound in bounds { + if first { + first = false; + } else { + self.nbsp(); + self.word_space("+"); + } - match bound { - GenericBound::Trait(tref, modifier) => { - if modifier == &TraitBoundModifier::Maybe { - self.word("?"); - } - self.print_poly_trait_ref(tref); + match bound { + GenericBound::Trait(tref, modifier) => { + if modifier == &TraitBoundModifier::Maybe { + self.word("?"); } - 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) { self.print_name(lifetime.ident.name) } - pub(crate) fn print_lifetime_bounds( - &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() { - if i != 0 { - self.word(" + "); - } - match bound { - ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt), - _ => panic!(), - } + pub(crate) fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) { + 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 match param.kind { ast::GenericParamKind::Lifetime => { 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 } => { 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 { s.space(); s.word_space("="); @@ -1630,7 +1632,10 @@ pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericPara s.space(); s.word_space(":"); 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 { s.space(); s.word_space("="); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 67b539a7ad41b77f25b231fe34c89773704ed1b8..f1caf22f3640fc9ced4e03f4df36e955e1ff58de 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -114,7 +114,10 @@ fn print_associated_type( self.word_space("type"); self.print_ident(ident); 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); if let Some(ty) = ty { self.space(); @@ -320,7 +323,10 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) { 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.word(" "); self.bopen(); @@ -347,7 +353,10 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) { } } 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.word(";"); self.end(); // end inner head-block @@ -618,14 +627,23 @@ pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { }) => { self.print_formal_generic_params(bound_generic_params); 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 { lifetime, 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, .. }) => { self.print_type(lhs_ty); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index acf892cec532871518b6a62f61c588067b215804..ba325d704228da3d92de52cddf0c8b1c08d37774 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -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.popen(); s.print_type(&mut_ty.ty); - s.print_type_bounds(" +", &bounds); + if !bounds.is_empty() { + s.word(" + "); + s.print_type_bounds(&bounds); + } s.pclose() }); diff --git a/src/test/pretty/where-clauses.rs b/src/test/pretty/where-clauses.rs index 5614a81b0eb410f0d7afe97ed090e244a296428f..4183799457b7fb0c744dc321fed0d1a92ee87185 100644 --- a/src/test/pretty/where-clauses.rs +++ b/src/test/pretty/where-clauses.rs @@ -2,4 +2,7 @@ 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() {}