1
Fork 0

Handle _ properly in a couple of places.

Currently (PatKind::Wild` (i.e. `_`) gets turned by
`lower_fn_params_to_names` into an empty identifier, which means it is
printed incorrectly by HIR pretty printing.

And likewise for `lower_fn_params_to_names`, which affects some error
messages.

This commit fixes them. This requires a slight tweak in a couple of
places to continue using parameter numbers in some error messages. And
it improves the output of `tests/ui/typeck/cyclic_type_ice.rs`:
`/* _ */` is a better suggestion than `/*  */`.
This commit is contained in:
Nicholas Nethercote 2025-03-14 08:40:43 +11:00
parent 9714f60f1d
commit 958bc7b365
6 changed files with 34 additions and 14 deletions

View file

@ -1516,7 +1516,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
PatKind::Ident(_, ident, _) => self.lower_ident(ident),
_ => Ident::new(kw::Empty, self.lower_span(param.pat.span)),
PatKind::Wild => Ident::new(kw::Underscore, self.lower_span(param.pat.span)),
_ => {
self.dcx().span_delayed_bug(
param.pat.span,
"non-ident/wild param pat must trigger an error",
);
Ident::new(kw::Empty, self.lower_span(param.pat.span))
}
}))
}

View file

@ -2712,11 +2712,12 @@ enum FnParam<'hir> {
Param(&'hir hir::Param<'hir>),
Name(&'hir Ident),
}
impl FnParam<'_> {
fn span(&self) -> Span {
match self {
Self::Param(x) => x.span,
Self::Name(x) => x.span,
Self::Param(param) => param.span,
Self::Name(ident) => ident.span,
}
}
@ -2724,15 +2725,23 @@ impl FnParam<'_> {
struct D<'a>(FnParam<'a>, usize);
impl fmt::Display for D<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self.0 {
FnParam::Param(x) if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind => {
// A "unique" param name is one that (a) exists, and (b) is guaranteed to be unique
// among the parameters, i.e. `_` does not count.
let unique_name = match self.0 {
FnParam::Param(param)
if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind =>
{
Some(ident.name)
}
FnParam::Name(ident)
if ident.name != kw::Empty && ident.name != kw::Underscore =>
{
Some(ident.name)
}
FnParam::Name(x) if x.name != kw::Empty => Some(x.name),
_ => None,
};
if let Some(name) = name {
write!(f, "`{name}`")
if let Some(unique_name) = unique_name {
write!(f, "`{unique_name}`")
} else {
write!(f, "parameter #{}", self.1 + 1)
}

View file

@ -281,8 +281,9 @@ impl<'tcx> TyCtxt<'tcx> {
}
pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> {
self.hir_body(id).params.iter().map(|arg| match arg.pat.kind {
self.hir_body(id).params.iter().map(|param| match param.pat.kind {
PatKind::Binding(_, _, ident, _) => ident,
PatKind::Wild => Ident::new(kw::Underscore, param.pat.span),
_ => Ident::empty(),
})
}

View file

@ -1998,7 +1998,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
.iter()
.enumerate()
.map(|(i, ident)| {
if ident.name.is_empty() || ident.name == kw::SelfLower {
if ident.name.is_empty()
|| ident.name == kw::Underscore
|| ident.name == kw::SelfLower
{
format!("arg{i}")
} else {
format!("{ident}")

View file

@ -27,12 +27,12 @@ impl S {
// because they had similar problems. But the pretty-printing tests currently
// can't contain compile errors.
fn bare_fn(x: fn(: u32, : u32, a: u32)) { }
fn bare_fn(x: fn(: u32, _: u32, a: u32)) { }
extern "C" {
unsafe fn foreign_fn(: u32, a: u32);
unsafe fn foreign_fn(_: u32, a: u32);
}
trait T {
fn trait_fn(: u32, : u32, a: u32);
fn trait_fn(: u32, _: u32, a: u32);
}

View file

@ -23,7 +23,7 @@ LL | let f = |_, _| ();
help: provide the argument
|
LL - f(f);
LL + f(/* */, /* */);
LL + f(/* _ */, /* _ */);
|
error: aborting due to 2 previous errors