Skip to content

Commit f5336a9

Browse files
Standardize arg suggestions between typeck and trait selection
1 parent b3edd9f commit f5336a9

File tree

4 files changed

+60
-54
lines changed

4 files changed

+60
-54
lines changed

compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9090
if ty.is_suggestable(self.tcx, false) {
9191
format!("/* {ty} */")
9292
} else {
93-
"".to_string()
93+
"/* value */".to_string()
9494
}
9595
})
9696
.collect::<Vec<_>>()

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+56-50
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ use rustc_hir::lang_items::LangItem;
2121
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
2222
use rustc_infer::infer::error_reporting::TypeErrCtxt;
2323
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
24+
use rustc_infer::infer::LateBoundRegionConversionTime;
2425
use rustc_middle::hir::map;
2526
use rustc_middle::ty::{
2627
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
2728
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
2829
ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
2930
};
3031
use rustc_middle::ty::{TypeAndMut, TypeckResults};
31-
use rustc_span::symbol::{kw, sym, Ident, Symbol};
32+
use rustc_span::symbol::{sym, Ident, Symbol};
3233
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
3334
use rustc_target::spec::abi;
3435
use std::fmt;
@@ -814,80 +815,85 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
814815
// Skipping binder here, remapping below
815816
let self_ty = trait_pred.self_ty().skip_binder();
816817

817-
let (def_id, output_ty, callable) = match *self_ty.kind() {
818-
ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
819-
ty::FnDef(def_id, _) => (
820-
def_id,
821-
self_ty.fn_sig(self.tcx).output(),
822-
match self.tcx.def_kind(def_id) {
823-
DefKind::Ctor(..) => "constructor",
824-
_ => "function",
825-
},
826-
),
818+
let (def_id, inputs, output, kind) = match *self_ty.kind() {
819+
ty::Closure(def_id, substs) => {
820+
let sig = substs.as_closure().sig();
821+
(def_id, sig.inputs().map_bound(|inputs| &inputs[1..]), sig.output(), "closure")
822+
}
823+
ty::FnDef(def_id, _) => {
824+
let sig = self_ty.fn_sig(self.tcx);
825+
(
826+
def_id,
827+
sig.inputs(),
828+
sig.output(),
829+
match self.tcx.def_kind(def_id) {
830+
DefKind::Ctor(..) => "constructor",
831+
_ => "function",
832+
},
833+
)
834+
}
827835
_ => return false,
828836
};
829-
let msg = format!("use parentheses to call the {}", callable);
830-
831-
// "We should really create a single list of bound vars from the combined vars
832-
// from the predicate and function, but instead we just liberate the function bound vars"
833-
let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
837+
let output = self.replace_bound_vars_with_fresh_vars(
838+
obligation.cause.span,
839+
LateBoundRegionConversionTime::FnCall,
840+
output,
841+
);
842+
let inputs = inputs.skip_binder().iter().map(|ty| {
843+
self.replace_bound_vars_with_fresh_vars(
844+
obligation.cause.span,
845+
LateBoundRegionConversionTime::FnCall,
846+
inputs.rebind(*ty),
847+
)
848+
});
834849

835850
// Remapping bound vars here
836-
let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
851+
let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
837852

838853
let new_obligation =
839854
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
840-
841855
if !self.predicate_must_hold_modulo_regions(&new_obligation) {
842856
return false;
843857
}
844858

845-
let hir = self.tcx.hir();
846859
// Get the name of the callable and the arguments to be used in the suggestion.
847-
let (snippet, sugg) = match hir.get_if_local(def_id) {
860+
let hir = self.tcx.hir();
861+
862+
let msg = format!("use parentheses to call the {}", kind);
863+
864+
let args = inputs
865+
.map(|ty| {
866+
if ty.is_suggestable(self.tcx, false) {
867+
format!("/* {ty} */")
868+
} else {
869+
"/* value */".to_string()
870+
}
871+
})
872+
.collect::<Vec<_>>()
873+
.join(", ");
874+
875+
let name = match hir.get_if_local(def_id) {
848876
Some(hir::Node::Expr(hir::Expr {
849-
kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
877+
kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
850878
..
851879
})) => {
852880
err.span_label(*fn_decl_span, "consider calling this closure");
853881
let Some(name) = self.get_closure_name(def_id, err, &msg) else {
854882
return false;
855883
};
856-
let args = fn_decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
857-
let sugg = format!("({})", args);
858-
(format!("{}{}", name, sugg), sugg)
884+
name.to_string()
859885
}
860-
Some(hir::Node::Item(hir::Item {
861-
ident,
862-
kind: hir::ItemKind::Fn(.., body_id),
863-
..
864-
})) => {
886+
Some(hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(..), .. })) => {
865887
err.span_label(ident.span, "consider calling this function");
866-
let body = hir.body(*body_id);
867-
let args = body
868-
.params
869-
.iter()
870-
.map(|arg| match &arg.pat.kind {
871-
hir::PatKind::Binding(_, _, ident, None)
872-
// FIXME: provide a better suggestion when encountering `SelfLower`, it
873-
// should suggest a method call.
874-
if ident.name != kw::SelfLower => ident.to_string(),
875-
_ => "_".to_string(),
876-
})
877-
.collect::<Vec<_>>()
878-
.join(", ");
879-
let sugg = format!("({})", args);
880-
(format!("{}{}", ident, sugg), sugg)
888+
ident.to_string()
881889
}
882-
Some(hir::Node::Ctor(data)) => {
890+
Some(hir::Node::Ctor(..)) => {
883891
let name = self.tcx.def_path_str(def_id);
884892
err.span_label(
885893
self.tcx.def_span(def_id),
886894
format!("consider calling the constructor for `{}`", name),
887895
);
888-
let args = data.fields().iter().map(|_| "_").collect::<Vec<_>>().join(", ");
889-
let sugg = format!("({})", args);
890-
(format!("{name}{sugg}"), sugg)
896+
name
891897
}
892898
_ => return false,
893899
};
@@ -901,11 +907,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
901907
err.span_suggestion_verbose(
902908
obligation.cause.span.shrink_to_hi(),
903909
&msg,
904-
sugg,
910+
format!("({args})"),
905911
Applicability::HasPlaceholders,
906912
);
907913
} else {
908-
err.help(&format!("{}: `{}`", msg, snippet));
914+
err.help(&format!("{msg}: `{name}({args})`"));
909915
}
910916
true
911917
}

src/test/ui/binop/issue-77910-1.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ LL | assert_eq!(foo, y);
1919
| ^^^^^^^^^^^^^^^^^^ `for<'a> fn(&'a i32) -> &'a i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
2020
|
2121
= help: the trait `Debug` is not implemented for fn item `for<'a> fn(&'a i32) -> &'a i32 {foo}`
22-
= help: use parentheses to call the function: `foo(s)`
22+
= help: use parentheses to call the function: `foo(/* &i32 */)`
2323
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
2424

2525
error: aborting due to 2 previous errors

src/test/ui/suggestions/call-on-unimplemented-ctor.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ LL | fn insert_resource<R: Resource>(resource: R) {}
1616
| ^^^^^^^^ required by this bound in `insert_resource`
1717
help: use parentheses to call the constructor
1818
|
19-
LL | insert_resource(Time(_));
20-
| +++
19+
LL | insert_resource(Time(/* u32 */));
20+
| +++++++++++
2121

2222
error: aborting due to previous error
2323

0 commit comments

Comments
 (0)