Skip to content

Commit e0d2f0a

Browse files
authored
Preserve and format type aliases in extern blocks (#4164)
2 parents f23a41a + a427a14 commit e0d2f0a

File tree

3 files changed

+90
-93
lines changed

3 files changed

+90
-93
lines changed

rustfmt-core/rustfmt-lib/src/items.rs

+63-86
Original file line numberDiff line numberDiff line change
@@ -1556,30 +1556,44 @@ fn format_tuple_struct(
15561556
Some(result)
15571557
}
15581558

1559-
fn rewrite_type_prefix(
1559+
fn rewrite_type<R: Rewrite>(
15601560
context: &RewriteContext<'_>,
15611561
indent: Indent,
1562-
prefix: &str,
15631562
ident: ast::Ident,
1563+
vis: &ast::Visibility,
15641564
generics: &ast::Generics,
1565+
generic_bounds_opt: Option<&ast::GenericBounds>,
1566+
rhs: Option<&R>,
15651567
) -> Option<String> {
15661568
let mut result = String::with_capacity(128);
1567-
result.push_str(prefix);
1569+
result.push_str(&format!("{}type ", format_visibility(context, vis)));
15681570
let ident_str = rewrite_ident(context, ident);
15691571

1570-
// 2 = `= `
15711572
if generics.params.is_empty() {
15721573
result.push_str(ident_str)
15731574
} else {
1575+
// 2 = `= `
15741576
let g_shape = Shape::indented(indent, context.config)
15751577
.offset_left(result.len())?
15761578
.sub_width(2)?;
15771579
let generics_str = rewrite_generics(context, ident_str, generics, g_shape)?;
15781580
result.push_str(&generics_str);
15791581
}
15801582

1583+
if let Some(bounds) = generic_bounds_opt {
1584+
if !bounds.is_empty() {
1585+
// 2 = `: `
1586+
let shape = Shape::indented(indent, context.config).offset_left(result.len() + 2)?;
1587+
let type_bounds = bounds.rewrite(context, shape).map(|s| format!(": {}", s))?;
1588+
result.push_str(&type_bounds);
1589+
}
1590+
}
1591+
15811592
let where_budget = context.budget(last_line_width(&result));
1582-
let option = WhereClauseOption::snuggled(&result);
1593+
let mut option = WhereClauseOption::snuggled(&result);
1594+
if rhs.is_none() {
1595+
option.suppress_comma();
1596+
}
15831597
let where_clause_str = rewrite_where_clause(
15841598
context,
15851599
&generics.where_clause,
@@ -1593,49 +1607,22 @@ fn rewrite_type_prefix(
15931607
)?;
15941608
result.push_str(&where_clause_str);
15951609

1596-
Some(result)
1597-
}
1598-
1599-
fn rewrite_type_item<R: Rewrite>(
1600-
context: &RewriteContext<'_>,
1601-
indent: Indent,
1602-
prefix: &str,
1603-
suffix: &str,
1604-
ident: ast::Ident,
1605-
rhs: &R,
1606-
generics: &ast::Generics,
1607-
vis: &ast::Visibility,
1608-
) -> Option<String> {
1609-
let mut result = String::with_capacity(128);
1610-
result.push_str(&rewrite_type_prefix(
1611-
context,
1612-
indent,
1613-
&format!("{}{} ", format_visibility(context, vis), prefix),
1614-
ident,
1615-
generics,
1616-
)?);
1610+
if let Some(ty) = rhs {
1611+
// If there's a where clause, add a newline before the assignment. Otherwise just add a
1612+
// space.
1613+
if !generics.where_clause.predicates.is_empty() {
1614+
result.push_str(&indent.to_string_with_newline(context.config));
1615+
} else {
1616+
result.push(' ');
1617+
}
1618+
let lhs = format!("{}=", result);
16171619

1618-
if generics.where_clause.predicates.is_empty() {
1619-
result.push_str(suffix);
1620+
// 1 = `;`
1621+
let shape = Shape::indented(indent, context.config).sub_width(1)?;
1622+
rewrite_assign_rhs(context, lhs, &*ty, shape).map(|s| s + ";")
16201623
} else {
1621-
result.push_str(&indent.to_string_with_newline(context.config));
1622-
result.push_str(suffix.trim_start());
1624+
Some(format!("{};", result))
16231625
}
1624-
1625-
// 1 = ";"
1626-
let rhs_shape = Shape::indented(indent, context.config).sub_width(1)?;
1627-
rewrite_assign_rhs(context, result, rhs, rhs_shape).map(|s| s + ";")
1628-
}
1629-
1630-
pub(crate) fn rewrite_type_alias(
1631-
context: &RewriteContext<'_>,
1632-
indent: Indent,
1633-
ident: ast::Ident,
1634-
ty: &ast::Ty,
1635-
generics: &ast::Generics,
1636-
vis: &ast::Visibility,
1637-
) -> Option<String> {
1638-
rewrite_type_item(context, indent, "type", " =", ident, ty, generics, vis)
16391626
}
16401627

16411628
pub(crate) fn rewrite_opaque_type(
@@ -1647,15 +1634,14 @@ pub(crate) fn rewrite_opaque_type(
16471634
vis: &ast::Visibility,
16481635
) -> Option<String> {
16491636
let opaque_type_bounds = OpaqueTypeBounds { generic_bounds };
1650-
rewrite_type_item(
1637+
rewrite_type(
16511638
context,
16521639
indent,
1653-
"type",
1654-
" =",
16551640
ident,
1656-
&opaque_type_bounds,
1657-
generics,
16581641
vis,
1642+
generics,
1643+
Some(generic_bounds),
1644+
Some(&opaque_type_bounds),
16591645
)
16601646
}
16611647

@@ -1897,40 +1883,24 @@ fn rewrite_static(
18971883
}
18981884
}
18991885

1900-
pub(crate) fn rewrite_associated_type(
1886+
pub(crate) fn rewrite_type_alias(
19011887
ident: ast::Ident,
19021888
ty_opt: Option<&ptr::P<ast::Ty>>,
19031889
generics: &ast::Generics,
19041890
generic_bounds_opt: Option<&ast::GenericBounds>,
19051891
context: &RewriteContext<'_>,
19061892
indent: Indent,
1893+
vis: &ast::Visibility,
19071894
) -> Option<String> {
1908-
let ident_str = rewrite_ident(context, ident);
1909-
// 5 = "type "
1910-
let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
1911-
let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
1912-
let prefix = format!("type {}", generics_str);
1913-
1914-
let type_bounds_str = if let Some(bounds) = generic_bounds_opt {
1915-
if bounds.is_empty() {
1916-
String::new()
1917-
} else {
1918-
// 2 = ": ".len()
1919-
let shape = Shape::indented(indent, context.config).offset_left(prefix.len() + 2)?;
1920-
bounds.rewrite(context, shape).map(|s| format!(": {}", s))?
1921-
}
1922-
} else {
1923-
String::new()
1924-
};
1925-
1926-
if let Some(ty) = ty_opt {
1927-
// 1 = `;`
1928-
let shape = Shape::indented(indent, context.config).sub_width(1)?;
1929-
let lhs = format!("{}{} =", prefix, type_bounds_str);
1930-
rewrite_assign_rhs(context, lhs, &**ty, shape).map(|s| s + ";")
1931-
} else {
1932-
Some(format!("{}{};", prefix, type_bounds_str))
1933-
}
1895+
rewrite_type(
1896+
context,
1897+
indent,
1898+
ident,
1899+
vis,
1900+
generics,
1901+
generic_bounds_opt,
1902+
ty_opt,
1903+
)
19341904
}
19351905

19361906
struct OpaqueType<'a> {
@@ -1973,13 +1943,14 @@ pub(crate) fn rewrite_opaque_impl_type(
19731943

19741944
pub(crate) fn rewrite_associated_impl_type(
19751945
ident: ast::Ident,
1946+
vis: &ast::Visibility,
19761947
defaultness: ast::Defaultness,
19771948
ty_opt: Option<&ptr::P<ast::Ty>>,
19781949
generics: &ast::Generics,
19791950
context: &RewriteContext<'_>,
19801951
indent: Indent,
19811952
) -> Option<String> {
1982-
let result = rewrite_associated_type(ident, ty_opt, generics, None, context, indent)?;
1953+
let result = rewrite_type_alias(ident, ty_opt, generics, None, context, indent, vis)?;
19831954

19841955
match defaultness {
19851956
ast::Defaultness::Default(..) => Some(format!("default {}", result)),
@@ -3156,14 +3127,20 @@ impl Rewrite for ast::ForeignItem {
31563127
// 1 = ;
31573128
rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
31583129
}
3159-
ast::ForeignItemKind::TyAlias(..) => {
3160-
let vis = format_visibility(context, &self.vis);
3161-
Some(format!(
3162-
"{}type {};",
3163-
vis,
3164-
rewrite_ident(context, self.ident)
3165-
))
3166-
}
3130+
ast::ForeignItemKind::TyAlias(
3131+
_,
3132+
ref generics,
3133+
ref generic_bounds,
3134+
ref type_default,
3135+
) => rewrite_type_alias(
3136+
self.ident,
3137+
type_default.as_ref(),
3138+
generics,
3139+
Some(generic_bounds),
3140+
&context,
3141+
shape.indent,
3142+
&self.vis,
3143+
),
31673144
ast::ForeignItemKind::MacCall(ref mac) => {
31683145
rewrite_macro(mac, None, context, shape, MacroPosition::Item)
31693146
}

rustfmt-core/rustfmt-lib/src/visitor.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ use crate::comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
99
use crate::config::{BraceStyle, Config};
1010
use crate::items::{
1111
format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
12-
rewrite_associated_impl_type, rewrite_associated_type, rewrite_extern_crate,
13-
rewrite_opaque_impl_type, rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig,
14-
StaticParts, StructParts,
12+
rewrite_associated_impl_type, rewrite_extern_crate, rewrite_opaque_impl_type,
13+
rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig, StaticParts, StructParts,
1514
};
1615
use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
1716
use crate::rewrite::{Rewrite, RewriteContext};
@@ -538,11 +537,12 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
538537
ast::ItemKind::TyAlias(_, ref generics, ref generic_bounds, ref ty) => match ty {
539538
Some(ty) => {
540539
let rewrite = rewrite_type_alias(
541-
&self.get_context(),
542-
self.block_indent,
543540
item.ident,
544-
&*ty,
541+
Some(&*ty),
545542
generics,
543+
Some(generic_bounds),
544+
&self.get_context(),
545+
self.block_indent,
546546
&item.vis,
547547
);
548548
self.push_rewrite(item.span, rewrite);
@@ -609,13 +609,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
609609
);
610610
}
611611
ast::AssocItemKind::TyAlias(_, ref generics, ref generic_bounds, ref type_default) => {
612-
let rewrite = rewrite_associated_type(
612+
let rewrite = rewrite_type_alias(
613613
ti.ident,
614614
type_default.as_ref(),
615615
generics,
616616
Some(generic_bounds),
617617
&self.get_context(),
618618
self.block_indent,
619+
&ti.vis,
619620
);
620621
self.push_rewrite(ti.span, rewrite);
621622
}
@@ -656,6 +657,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
656657
let rewrite_associated = || {
657658
rewrite_associated_impl_type(
658659
ii.ident,
660+
&ii.vis,
659661
defaultness,
660662
ty.as_ref(),
661663
generics,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
extern "C" {
2+
type A: Ord;
3+
4+
type A<'a>
5+
where
6+
'a: 'static;
7+
8+
type A<T: Ord>
9+
where
10+
T: 'static;
11+
12+
type A = u8;
13+
14+
type A<'a: 'static, T: Ord + 'static>: Eq + PartialEq
15+
where
16+
T: 'static + Copy,
17+
= Vec<u8>;
18+
}

0 commit comments

Comments
 (0)