Rollup merge of #138482 - nnethercote:fix-hir-printing, r=compiler-errors
Fix HIR printing of parameters HIR pretty printing does the wrong thing for anonymous parameters, and there is no test coverage for it. This PR remedies both of those things. r? ``@lcnr``
This commit is contained in:
commit
370f8fb99d
8 changed files with 115 additions and 24 deletions
|
@ -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))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -2148,9 +2148,11 @@ impl<'a> State<'a> {
|
|||
s.print_implicit_self(&decl.implicit_self);
|
||||
} else {
|
||||
if let Some(arg_name) = arg_names.get(i) {
|
||||
s.word(arg_name.to_string());
|
||||
s.word(":");
|
||||
s.space();
|
||||
if arg_name.name != kw::Empty {
|
||||
s.word(arg_name.to_string());
|
||||
s.word(":");
|
||||
s.space();
|
||||
}
|
||||
} else if let Some(body_id) = body_id {
|
||||
s.ann.nested(s, Nested::BodyParamPat(body_id, i));
|
||||
s.word(":");
|
||||
|
|
|
@ -19,7 +19,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
|
|||
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
|
||||
use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
|
||||
|
@ -2679,7 +2679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?;
|
||||
debug_assert_eq!(params.len(), fn_inputs.len());
|
||||
Some((
|
||||
fn_inputs.zip(params.iter().map(|param| FnParam::Name(param))).collect(),
|
||||
fn_inputs.zip(params.iter().map(|¶m| FnParam::Name(param))).collect(),
|
||||
generics,
|
||||
))
|
||||
}
|
||||
|
@ -2710,23 +2710,14 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> {
|
|||
#[derive(Clone, Copy)]
|
||||
enum FnParam<'hir> {
|
||||
Param(&'hir hir::Param<'hir>),
|
||||
Name(&'hir Ident),
|
||||
Name(Ident),
|
||||
}
|
||||
|
||||
impl FnParam<'_> {
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
Self::Param(x) => x.span,
|
||||
Self::Name(x) => x.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<Symbol> {
|
||||
match self {
|
||||
Self::Param(x) if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind => {
|
||||
Some(ident.name)
|
||||
}
|
||||
Self::Name(x) if x.name != kw::Empty => Some(x.name),
|
||||
_ => None,
|
||||
Self::Param(param) => param.span,
|
||||
Self::Name(ident) => ident.span,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2734,8 +2725,23 @@ impl FnParam<'_> {
|
|||
struct D<'a>(FnParam<'a>, usize);
|
||||
impl fmt::Display for D<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(name) = self.0.name() {
|
||||
write!(f, "`{name}`")
|
||||
// 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)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(unique_name) = unique_name {
|
||||
write!(f, "`{unique_name}`")
|
||||
} else {
|
||||
write!(f, "parameter #{}", self.1 + 1)
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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}")
|
||||
|
|
38
tests/pretty/hir-fn-params.pp
Normal file
38
tests/pretty/hir-fn-params.pp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#[prelude_import]
|
||||
use ::std::prelude::rust_2015::*;
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
//@ pretty-compare-only
|
||||
//@ pretty-mode:hir
|
||||
//@ pp-exact:hir-fn-params.pp
|
||||
|
||||
// This tests the pretty-printing of various kinds of function parameters.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Normal functions and methods.
|
||||
|
||||
fn normal_fn(_: u32, a: u32) { }
|
||||
|
||||
struct S;
|
||||
impl S {
|
||||
fn method(_: u32, a: u32) { }
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// More exotic forms, which get a different pretty-printing path. In the past,
|
||||
// anonymous params and `_` params printed incorrectly, e.g. `fn(u32, _: u32)`
|
||||
// was printed as `fn(: u32, : u32)`.
|
||||
//
|
||||
// Ideally we would also test invalid patterns, e.g. `fn(1: u32, &a: u32)`,
|
||||
// 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)) { }
|
||||
|
||||
extern "C" {
|
||||
unsafe fn foreign_fn(_: u32, a: u32);
|
||||
}
|
||||
|
||||
trait T {
|
||||
fn trait_fn(u32, _: u32, a: u32);
|
||||
}
|
34
tests/pretty/hir-fn-params.rs
Normal file
34
tests/pretty/hir-fn-params.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
//@ pretty-compare-only
|
||||
//@ pretty-mode:hir
|
||||
//@ pp-exact:hir-fn-params.pp
|
||||
|
||||
// This tests the pretty-printing of various kinds of function parameters.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Normal functions and methods.
|
||||
|
||||
fn normal_fn(_: u32, a: u32) {}
|
||||
|
||||
struct S;
|
||||
impl S {
|
||||
fn method(_: u32, a: u32) {}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// More exotic forms, which get a different pretty-printing path. In the past,
|
||||
// anonymous params and `_` params printed incorrectly, e.g. `fn(u32, _: u32)`
|
||||
// was printed as `fn(: u32, : u32)`.
|
||||
//
|
||||
// Ideally we would also test invalid patterns, e.g. `fn(1: u32, &a: u32)`,
|
||||
// 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)) {}
|
||||
|
||||
extern "C" {
|
||||
fn foreign_fn(_: u32, a: u32);
|
||||
}
|
||||
|
||||
trait T {
|
||||
fn trait_fn(u32, _: u32, a: u32);
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue