diff --git a/src/items.rs b/src/items.rs index 6b81dbaf7966..7da84bfe68f6 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1752,11 +1752,10 @@ pub fn rewrite_associated_impl_type( ident: ast::Ident, defaultness: ast::Defaultness, ty_opt: Option<&ptr::P>, - generic_bounds_opt: Option<&ast::GenericBounds>, context: &RewriteContext, indent: Indent, ) -> Option { - let result = rewrite_associated_type(ident, ty_opt, generic_bounds_opt, context, indent)?; + let result = rewrite_associated_type(ident, ty_opt, None, context, indent)?; match defaultness { ast::Defaultness::Default => Some(format!("default {}", result)), diff --git a/src/types.rs b/src/types.rs index d6e4001eacfc..a67ba8765911 100644 --- a/src/types.rs +++ b/src/types.rs @@ -27,8 +27,8 @@ use shape::Shape; use spanned::Spanned; use utils::{ - colon_spaces, extra_offset, first_line_width, format_abi, format_mutability, last_line_width, - mk_sp, rewrite_ident, + colon_spaces, extra_offset, first_line_width, format_abi, format_mutability, + last_line_extendable, last_line_width, mk_sp, rewrite_ident, }; #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -733,15 +733,28 @@ fn rewrite_bare_fn( Some(result) } -fn join_bounds( +fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool { + let is_trait = |b: &ast::GenericBound| match b { + ast::GenericBound::Outlives(..) => false, + ast::GenericBound::Trait(..) => true, + }; + let is_lifetime = |b: &ast::GenericBound| !is_trait(b); + let last_trait_index = generic_bounds.iter().rposition(is_trait); + let first_lifetime_index = generic_bounds.iter().position(is_lifetime); + match (last_trait_index, first_lifetime_index) { + (Some(last_trait_index), Some(first_lifetime_index)) => { + last_trait_index < first_lifetime_index + } + _ => true, + } +} + +fn join_bounds( context: &RewriteContext, shape: Shape, - items: &[T], + items: &[ast::GenericBound], need_indent: bool, -) -> Option -where - T: Rewrite, -{ +) -> Option { // Try to join types in a single line let joiner = match context.config.type_punctuation_density() { TypeDensity::Compressed => "+", @@ -752,7 +765,7 @@ fn join_bounds( .map(|item| item.rewrite(context, shape)) .collect::>>()?; let result = type_strs.join(joiner); - if items.len() == 1 || (!result.contains('\n') && result.len() <= shape.width) { + if items.len() <= 1 || (!result.contains('\n') && result.len() <= shape.width) { return Some(result); } @@ -769,8 +782,26 @@ fn join_bounds( (type_strs, shape.indent) }; - let joiner = format!("{}+ ", offset.to_string_with_newline(context.config)); - Some(type_strs.join(&joiner)) + let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b { + ast::GenericBound::Outlives(..) => true, + ast::GenericBound::Trait(..) => last_line_extendable(s), + }; + let mut result = String::with_capacity(128); + result.push_str(&type_strs[0]); + let mut can_be_put_on_the_same_line = is_bound_extendable(&result, &items[0]); + let generic_bounds_in_order = is_generic_bounds_in_order(items); + for (bound, bound_str) in items[1..].iter().zip(type_strs[1..].iter()) { + if generic_bounds_in_order && can_be_put_on_the_same_line { + result.push_str(joiner); + } else { + result.push_str(&offset.to_string_with_newline(context.config)); + result.push_str("+ "); + } + result.push_str(bound_str); + can_be_put_on_the_same_line = is_bound_extendable(bound_str, bound); + } + + Some(result) } pub fn can_be_overflowed_type(context: &RewriteContext, ty: &ast::Ty, len: usize) -> bool { diff --git a/src/visitor.rs b/src/visitor.rs index 4fabb3301fc0..fdbc9907f22a 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -515,7 +515,6 @@ pub fn visit_impl_item(&mut self, ii: &ast::ImplItem) { ii.ident, ii.defaultness, Some(ty), - None, &self.get_context(), self.block_indent, ); diff --git a/tests/source/type.rs b/tests/source/type.rs index 9477af52443c..8d941fc0ab7f 100644 --- a/tests/source/type.rs +++ b/tests/source/type.rs @@ -38,3 +38,47 @@ pub fn pop_callback( self.query_callbacks()(&query_id) } } + +// #2859 +pub fn do_something<'a, T: Trait1 + Trait2 + 'a>(&fooo: u32) -> impl Future< + Item = ( + impl Future + 'a, + impl Future + 'a, +impl Future + 'a, + ), + Error = SomeError, + > + + + 'a { +} + +pub fn do_something<'a, T: Trait1 + Trait2 + 'a>( &fooo: u32, +) -> impl Future< + Item = ( +impl Future + 'a, + impl Future + 'a, + impl Future + 'a, + ), + Error = SomeError, + > + + Future< + Item = ( + impl Future + 'a, +impl Future + 'a, + impl Future + 'a, + ), + Error = SomeError, + > + + Future< + Item = ( + impl Future + 'a, + impl Future + 'a, + impl Future + 'a, + ), + Error = SomeError, + > + + + 'a + 'b + + 'c { +} diff --git a/tests/target/type.rs b/tests/target/type.rs index 95f7ff3d5d21..b3a56d9ed2d7 100644 --- a/tests/target/type.rs +++ b/tests/target/type.rs @@ -42,3 +42,42 @@ pub fn pop_callback( self.query_callbacks()(&query_id) } } + +// #2859 +pub fn do_something<'a, T: Trait1 + Trait2 + 'a>( + &fooo: u32, +) -> impl Future< + Item = ( + impl Future + 'a, + impl Future + 'a, + impl Future + 'a, + ), + Error = SomeError, +> + 'a { +} + +pub fn do_something<'a, T: Trait1 + Trait2 + 'a>( + &fooo: u32, +) -> impl Future< + Item = ( + impl Future + 'a, + impl Future + 'a, + impl Future + 'a, + ), + Error = SomeError, +> + Future< + Item = ( + impl Future + 'a, + impl Future + 'a, + impl Future + 'a, + ), + Error = SomeError, +> + Future< + Item = ( + impl Future + 'a, + impl Future + 'a, + impl Future + 'a, + ), + Error = SomeError, +> + 'a + 'b + 'c { +}