Skip to content

Commit 17828f6

Browse files
authored
Unrolled build for rust-lang#139913
Rollup merge of rust-lang#139913 - fmease:rustdoc-fix-fn-param-handling, r=GuillaumeGomez rustdoc/clean: Fix lowering of fn params (fixes correctness & HIR vs. middle parity regressions) **(0)** PR rust-lang#136411 aimed to stop rendering unnamed params of fn ptr types as underscores in the common case (e.g., `fn(_: i32)` → `fn(i32)`) to make the rendered output stylistically more conventional. **(0.a)** However, since the cleaning fn that the PR modified is also used for lowering the HIR params of foreign fns and required assoc fns in traits, it accidentally butchered the rendering of the latter two: ```rs pub trait Trait { fn assoc_fn(_: i32); } // as well as (Rust 2015 only): fn assoc_fn(i32); unsafe extern "C" { pub fn foreign_fn(_: i32); } // Since 1.86 the fns above gets mis-rendered as: pub fn assoc_fn(: i32) // <-- BUTCHERED pub unsafe extern "C" fn foreign_fn(: i32) // <-- BUTCHERED ``` **(0.b)** Furthermore, it broke parity with middle cleaning (which includes inlined cross-crate re-exports) re-regressing parts of rust-lang#44306 I once fixed in PR rust-lang#103885. **(1)** Lastly, PR rust-lang#139035 introduced an ICE triggered by the following input file: ```rs trait Trait { fn anon(()) {} } // internal error: entered unreachable code ``` --- This PR fixes all of these regressions and in the first commit renames several types and fns to be more ~~correct~~ descriptive and legible. ~~It also refactors `Param.name` to be of type `Option<Symbol>` instead `Symbol` (where `None` ~ `kw::Empty`), so rendering mistakes like that can no longer creep in like that (ignoring tests). CC rust-lang#137978.~~ Independently done in PR rust-lang#139846 a day prior.
2 parents 6a0bd27 + 82ff0a0 commit 17828f6

File tree

14 files changed

+186
-167
lines changed

14 files changed

+186
-167
lines changed

Diff for: src/librustdoc/clean/mod.rs

+82-106
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ fn clean_fn_or_proc_macro<'tcx>(
10521052
match macro_kind {
10531053
Some(kind) => clean_proc_macro(item, name, kind, cx),
10541054
None => {
1055-
let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
1055+
let mut func = clean_function(cx, sig, generics, ParamsSrc::Body(body_id));
10561056
clean_fn_decl_legacy_const_generics(&mut func, attrs);
10571057
FunctionItem(func)
10581058
}
@@ -1071,16 +1071,11 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib
10711071
for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() {
10721072
match literal.kind {
10731073
ast::LitKind::Int(a, _) => {
1074-
let param = func.generics.params.remove(0);
1075-
if let GenericParamDef {
1076-
name,
1077-
kind: GenericParamDefKind::Const { ty, .. },
1078-
..
1079-
} = param
1080-
{
1081-
func.decl.inputs.values.insert(
1074+
let GenericParamDef { name, kind, .. } = func.generics.params.remove(0);
1075+
if let GenericParamDefKind::Const { ty, .. } = kind {
1076+
func.decl.inputs.insert(
10821077
a.get() as _,
1083-
Argument { name: Some(name), type_: *ty, is_const: true },
1078+
Parameter { name: Some(name), type_: *ty, is_const: true },
10841079
);
10851080
} else {
10861081
panic!("unexpected non const in position {pos}");
@@ -1092,7 +1087,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib
10921087
}
10931088
}
10941089

1095-
enum FunctionArgs<'tcx> {
1090+
enum ParamsSrc<'tcx> {
10961091
Body(hir::BodyId),
10971092
Idents(&'tcx [Option<Ident>]),
10981093
}
@@ -1101,86 +1096,62 @@ fn clean_function<'tcx>(
11011096
cx: &mut DocContext<'tcx>,
11021097
sig: &hir::FnSig<'tcx>,
11031098
generics: &hir::Generics<'tcx>,
1104-
args: FunctionArgs<'tcx>,
1099+
params: ParamsSrc<'tcx>,
11051100
) -> Box<Function> {
11061101
let (generics, decl) = enter_impl_trait(cx, |cx| {
1107-
// NOTE: generics must be cleaned before args
1102+
// NOTE: Generics must be cleaned before params.
11081103
let generics = clean_generics(generics, cx);
1109-
let args = match args {
1110-
FunctionArgs::Body(body_id) => {
1111-
clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id)
1112-
}
1113-
FunctionArgs::Idents(idents) => {
1114-
clean_args_from_types_and_names(cx, sig.decl.inputs, idents)
1115-
}
1104+
let params = match params {
1105+
ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl.inputs, body_id),
1106+
// Let's not perpetuate anon params from Rust 2015; use `_` for them.
1107+
ParamsSrc::Idents(idents) => clean_params(cx, sig.decl.inputs, idents, |ident| {
1108+
Some(ident.map_or(kw::Underscore, |ident| ident.name))
1109+
}),
11161110
};
1117-
let decl = clean_fn_decl_with_args(cx, sig.decl, Some(&sig.header), args);
1111+
let decl = clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params);
11181112
(generics, decl)
11191113
});
11201114
Box::new(Function { decl, generics })
11211115
}
11221116

1123-
fn clean_args_from_types_and_names<'tcx>(
1117+
fn clean_params<'tcx>(
11241118
cx: &mut DocContext<'tcx>,
11251119
types: &[hir::Ty<'tcx>],
11261120
idents: &[Option<Ident>],
1127-
) -> Arguments {
1128-
fn nonempty_name(ident: &Option<Ident>) -> Option<Symbol> {
1129-
if let Some(ident) = ident
1130-
&& ident.name != kw::Underscore
1131-
{
1132-
Some(ident.name)
1133-
} else {
1134-
None
1135-
}
1136-
}
1137-
1138-
// If at least one argument has a name, use `_` as the name of unnamed
1139-
// arguments. Otherwise omit argument names.
1140-
let default_name = if idents.iter().any(|ident| nonempty_name(ident).is_some()) {
1141-
Some(kw::Underscore)
1142-
} else {
1143-
None
1144-
};
1145-
1146-
Arguments {
1147-
values: types
1148-
.iter()
1149-
.enumerate()
1150-
.map(|(i, ty)| Argument {
1151-
type_: clean_ty(ty, cx),
1152-
name: idents.get(i).and_then(nonempty_name).or(default_name),
1153-
is_const: false,
1154-
})
1155-
.collect(),
1156-
}
1121+
postprocess: impl Fn(Option<Ident>) -> Option<Symbol>,
1122+
) -> Vec<Parameter> {
1123+
types
1124+
.iter()
1125+
.enumerate()
1126+
.map(|(i, ty)| Parameter {
1127+
name: postprocess(idents[i]),
1128+
type_: clean_ty(ty, cx),
1129+
is_const: false,
1130+
})
1131+
.collect()
11571132
}
11581133

1159-
fn clean_args_from_types_and_body_id<'tcx>(
1134+
fn clean_params_via_body<'tcx>(
11601135
cx: &mut DocContext<'tcx>,
11611136
types: &[hir::Ty<'tcx>],
11621137
body_id: hir::BodyId,
1163-
) -> Arguments {
1164-
let body = cx.tcx.hir_body(body_id);
1165-
1166-
Arguments {
1167-
values: types
1168-
.iter()
1169-
.zip(body.params)
1170-
.map(|(ty, param)| Argument {
1171-
name: Some(name_from_pat(param.pat)),
1172-
type_: clean_ty(ty, cx),
1173-
is_const: false,
1174-
})
1175-
.collect(),
1176-
}
1138+
) -> Vec<Parameter> {
1139+
types
1140+
.iter()
1141+
.zip(cx.tcx.hir_body(body_id).params)
1142+
.map(|(ty, param)| Parameter {
1143+
name: Some(name_from_pat(param.pat)),
1144+
type_: clean_ty(ty, cx),
1145+
is_const: false,
1146+
})
1147+
.collect()
11771148
}
11781149

1179-
fn clean_fn_decl_with_args<'tcx>(
1150+
fn clean_fn_decl_with_params<'tcx>(
11801151
cx: &mut DocContext<'tcx>,
11811152
decl: &hir::FnDecl<'tcx>,
11821153
header: Option<&hir::FnHeader>,
1183-
args: Arguments,
1154+
params: Vec<Parameter>,
11841155
) -> FnDecl {
11851156
let mut output = match decl.output {
11861157
hir::FnRetTy::Return(typ) => clean_ty(typ, cx),
@@ -1191,18 +1162,14 @@ fn clean_fn_decl_with_args<'tcx>(
11911162
{
11921163
output = output.sugared_async_return_type();
11931164
}
1194-
FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
1165+
FnDecl { inputs: params, output, c_variadic: decl.c_variadic }
11951166
}
11961167

11971168
fn clean_poly_fn_sig<'tcx>(
11981169
cx: &mut DocContext<'tcx>,
11991170
did: Option<DefId>,
12001171
sig: ty::PolyFnSig<'tcx>,
12011172
) -> FnDecl {
1202-
let mut names = did.map_or(&[] as &[_], |did| cx.tcx.fn_arg_idents(did)).iter();
1203-
1204-
// We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
1205-
// but shouldn't change any code meaning.
12061173
let mut output = clean_middle_ty(sig.output(), cx, None, None);
12071174

12081175
// If the return type isn't an `impl Trait`, we can safely assume that this
@@ -1215,25 +1182,25 @@ fn clean_poly_fn_sig<'tcx>(
12151182
output = output.sugared_async_return_type();
12161183
}
12171184

1218-
FnDecl {
1219-
output,
1220-
c_variadic: sig.skip_binder().c_variadic,
1221-
inputs: Arguments {
1222-
values: sig
1223-
.inputs()
1224-
.iter()
1225-
.map(|t| Argument {
1226-
type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None),
1227-
name: Some(if let Some(Some(ident)) = names.next() {
1228-
ident.name
1229-
} else {
1230-
kw::Underscore
1231-
}),
1232-
is_const: false,
1233-
})
1234-
.collect(),
1235-
},
1236-
}
1185+
let mut idents = did.map(|did| cx.tcx.fn_arg_idents(did)).unwrap_or_default().iter().copied();
1186+
1187+
// If this comes from a fn item, let's not perpetuate anon params from Rust 2015; use `_` for them.
1188+
// If this comes from a fn ptr ty, we just keep params unnamed since it's more conventional stylistically.
1189+
// Since the param name is not part of the semantic type, these params never bear a name unlike
1190+
// in the HIR case, thus we can't peform any fancy fallback logic unlike `clean_bare_fn_ty`.
1191+
let fallback = did.map(|_| kw::Underscore);
1192+
1193+
let params = sig
1194+
.inputs()
1195+
.iter()
1196+
.map(|ty| Parameter {
1197+
name: idents.next().flatten().map(|ident| ident.name).or(fallback),
1198+
type_: clean_middle_ty(ty.map_bound(|ty| *ty), cx, None, None),
1199+
is_const: false,
1200+
})
1201+
.collect();
1202+
1203+
FnDecl { inputs: params, output, c_variadic: sig.skip_binder().c_variadic }
12371204
}
12381205

12391206
fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
@@ -1273,11 +1240,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
12731240
RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx)))
12741241
}
12751242
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
1276-
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
1243+
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body));
12771244
MethodItem(m, None)
12781245
}
12791246
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
1280-
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Idents(idents));
1247+
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents));
12811248
RequiredMethodItem(m)
12821249
}
12831250
hir::TraitItemKind::Type(bounds, Some(default)) => {
@@ -1318,7 +1285,7 @@ pub(crate) fn clean_impl_item<'tcx>(
13181285
type_: clean_ty(ty, cx),
13191286
})),
13201287
hir::ImplItemKind::Fn(ref sig, body) => {
1321-
let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body));
1288+
let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body));
13221289
let defaultness = cx.tcx.defaultness(impl_.owner_id);
13231290
MethodItem(m, Some(defaultness))
13241291
}
@@ -1390,14 +1357,14 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
13901357
}
13911358
ty::AssocItemContainer::Trait => tcx.types.self_param,
13921359
};
1393-
let self_arg_ty =
1360+
let self_param_ty =
13941361
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
1395-
if self_arg_ty == self_ty {
1396-
item.decl.inputs.values[0].type_ = SelfTy;
1397-
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind()
1362+
if self_param_ty == self_ty {
1363+
item.decl.inputs[0].type_ = SelfTy;
1364+
} else if let ty::Ref(_, ty, _) = *self_param_ty.kind()
13981365
&& ty == self_ty
13991366
{
1400-
match item.decl.inputs.values[0].type_ {
1367+
match item.decl.inputs[0].type_ {
14011368
BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
14021369
_ => unreachable!(),
14031370
}
@@ -2611,15 +2578,25 @@ fn clean_bare_fn_ty<'tcx>(
26112578
cx: &mut DocContext<'tcx>,
26122579
) -> BareFunctionDecl {
26132580
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
2614-
// NOTE: generics must be cleaned before args
2581+
// NOTE: Generics must be cleaned before params.
26152582
let generic_params = bare_fn
26162583
.generic_params
26172584
.iter()
26182585
.filter(|p| !is_elided_lifetime(p))
26192586
.map(|x| clean_generic_param(cx, None, x))
26202587
.collect();
2621-
let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_idents);
2622-
let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args);
2588+
// Since it's more conventional stylistically, elide the name of all params called `_`
2589+
// unless there's at least one interestingly named param in which case don't elide any
2590+
// name since mixing named and unnamed params is less legible.
2591+
let filter = |ident: Option<Ident>| {
2592+
ident.map(|ident| ident.name).filter(|&ident| ident != kw::Underscore)
2593+
};
2594+
let fallback =
2595+
bare_fn.param_idents.iter().copied().find_map(filter).map(|_| kw::Underscore);
2596+
let params = clean_params(cx, bare_fn.decl.inputs, bare_fn.param_idents, |ident| {
2597+
filter(ident).or(fallback)
2598+
});
2599+
let decl = clean_fn_decl_with_params(cx, bare_fn.decl, None, params);
26232600
(generic_params, decl)
26242601
});
26252602
BareFunctionDecl { safety: bare_fn.safety, abi: bare_fn.abi, decl, generic_params }
@@ -2629,7 +2606,6 @@ fn clean_unsafe_binder_ty<'tcx>(
26292606
unsafe_binder_ty: &hir::UnsafeBinderTy<'tcx>,
26302607
cx: &mut DocContext<'tcx>,
26312608
) -> UnsafeBinderTy {
2632-
// NOTE: generics must be cleaned before args
26332609
let generic_params = unsafe_binder_ty
26342610
.generic_params
26352611
.iter()
@@ -3155,7 +3131,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
31553131
cx.with_param_env(def_id, |cx| {
31563132
let kind = match item.kind {
31573133
hir::ForeignItemKind::Fn(sig, idents, generics) => ForeignFunctionItem(
3158-
clean_function(cx, &sig, generics, FunctionArgs::Idents(idents)),
3134+
clean_function(cx, &sig, generics, ParamsSrc::Idents(idents)),
31593135
sig.header.safety(),
31603136
),
31613137
hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(

Diff for: src/librustdoc/clean/types.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -1407,32 +1407,28 @@ pub(crate) struct Function {
14071407

14081408
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
14091409
pub(crate) struct FnDecl {
1410-
pub(crate) inputs: Arguments,
1410+
pub(crate) inputs: Vec<Parameter>,
14111411
pub(crate) output: Type,
14121412
pub(crate) c_variadic: bool,
14131413
}
14141414

14151415
impl FnDecl {
14161416
pub(crate) fn receiver_type(&self) -> Option<&Type> {
1417-
self.inputs.values.first().and_then(|v| v.to_receiver())
1417+
self.inputs.first().and_then(|v| v.to_receiver())
14181418
}
14191419
}
14201420

1421+
/// A function parameter.
14211422
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1422-
pub(crate) struct Arguments {
1423-
pub(crate) values: Vec<Argument>,
1424-
}
1425-
1426-
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1427-
pub(crate) struct Argument {
1428-
pub(crate) type_: Type,
1423+
pub(crate) struct Parameter {
14291424
pub(crate) name: Option<Symbol>,
1425+
pub(crate) type_: Type,
14301426
/// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
14311427
/// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
14321428
pub(crate) is_const: bool,
14331429
}
14341430

1435-
impl Argument {
1431+
impl Parameter {
14361432
pub(crate) fn to_receiver(&self) -> Option<&Type> {
14371433
if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
14381434
}

Diff for: src/librustdoc/clean/utils.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,12 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
303303
debug!("trying to get a name from pattern: {p:?}");
304304

305305
Symbol::intern(&match &p.kind {
306-
// FIXME(never_patterns): does this make sense?
307-
PatKind::Missing => unreachable!(),
308-
PatKind::Wild
309-
| PatKind::Err(_)
306+
PatKind::Err(_)
307+
| PatKind::Missing // Let's not perpetuate anon params from Rust 2015; use `_` for them.
310308
| PatKind::Never
309+
| PatKind::Range(..)
311310
| PatKind::Struct(..)
312-
| PatKind::Range(..) => {
311+
| PatKind::Wild => {
313312
return kw::Underscore;
314313
}
315314
PatKind::Binding(_, _, ident, _) => return ident.name,

0 commit comments

Comments
 (0)