Skip to content

Commit 103b0e3

Browse files
authored
Rollup merge of rust-lang#72271 - rakshith-ravi:master, r=varkor
Improve compiler error message for wrong generic parameter order - Added optional "help" parameter that shows a help message on the compiler error if required. - Added a simple ordered parameter as a sample help. @varkor will make more changes as required. Let me know if I'm heading in the right direction. Fixes rust-lang#68437 r? @varkor
2 parents c062ce5 + 0624a5a commit 103b0e3

File tree

3 files changed

+70
-6
lines changed

3 files changed

+70
-6
lines changed

src/librustc_typeck/astconv.rs

+67-6
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
use crate::collect::PlaceholderHirTyCollector;
99
use crate::middle::resolve_lifetime as rl;
1010
use crate::require_c_abi_if_c_variadic;
11-
use rustc_ast::ast::ParamKindOrd;
12-
use rustc_ast::util::lev_distance::find_best_match_for_name;
11+
use rustc_ast::{ast::ParamKindOrd, util::lev_distance::find_best_match_for_name};
1312
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1413
use rustc_errors::ErrorReported;
1514
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, FatalError};
@@ -27,7 +26,7 @@ use rustc_middle::ty::{GenericParamDef, GenericParamDefKind};
2726
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS};
2827
use rustc_session::parse::feature_err;
2928
use rustc_session::Session;
30-
use rustc_span::symbol::{sym, Ident, Symbol};
29+
use rustc_span::symbol::{kw, sym, Ident, Symbol};
3130
use rustc_span::{MultiSpan, Span, DUMMY_SP};
3231
use rustc_target::spec::abi;
3332
use rustc_trait_selection::traits;
@@ -475,7 +474,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
475474

476475
/// Report an error that a generic argument did not match the generic parameter that was
477476
/// expected.
478-
fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) {
477+
fn generic_arg_mismatch_err(
478+
sess: &Session,
479+
arg: &GenericArg<'_>,
480+
kind: &'static str,
481+
help: Option<&str>,
482+
) {
479483
let mut err = struct_span_err!(
480484
sess,
481485
arg.span(),
@@ -503,6 +507,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
503507
let (first, last) =
504508
if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
505509
err.note(&format!("{} arguments must be provided before {} arguments", first, last));
510+
511+
if let Some(help) = help {
512+
err.help(help);
513+
}
506514
err.emit();
507515
}
508516

@@ -648,7 +656,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
648656
if arg_count.correct.is_ok()
649657
&& arg_count.explicit_late_bound == ExplicitLateBound::No
650658
{
651-
Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr());
659+
// We're going to iterate over the parameters to sort them out, and
660+
// show that order to the user as a possible order for the parameters
661+
let mut param_types_present = defs
662+
.params
663+
.clone()
664+
.into_iter()
665+
.map(|param| {
666+
(
667+
match param.kind {
668+
GenericParamDefKind::Lifetime => {
669+
ParamKindOrd::Lifetime
670+
}
671+
GenericParamDefKind::Type { .. } => {
672+
ParamKindOrd::Type
673+
}
674+
GenericParamDefKind::Const => {
675+
ParamKindOrd::Const
676+
}
677+
},
678+
param,
679+
)
680+
})
681+
.collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
682+
param_types_present.sort_by_key(|(ord, _)| *ord);
683+
let (mut param_types_present, ordered_params): (
684+
Vec<ParamKindOrd>,
685+
Vec<GenericParamDef>,
686+
) = param_types_present.into_iter().unzip();
687+
param_types_present.dedup();
688+
689+
Self::generic_arg_mismatch_err(
690+
tcx.sess,
691+
arg,
692+
kind.descr(),
693+
Some(&format!(
694+
"reorder the arguments: {}: `<{}>`",
695+
param_types_present
696+
.into_iter()
697+
.map(|ord| format!("{}s", ord.to_string()))
698+
.collect::<Vec<String>>()
699+
.join(", then "),
700+
ordered_params
701+
.into_iter()
702+
.filter_map(|param| {
703+
if param.name == kw::SelfUpper {
704+
None
705+
} else {
706+
Some(param.name.to_string())
707+
}
708+
})
709+
.collect::<Vec<String>>()
710+
.join(", ")
711+
)),
712+
);
652713
}
653714

654715
// We've reported the error, but we want to make sure that this
@@ -680,7 +741,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
680741
assert_eq!(kind, "lifetime");
681742
let provided =
682743
force_infer_lt.expect("lifetimes ought to have been inferred");
683-
Self::generic_arg_mismatch_err(tcx.sess, provided, kind);
744+
Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None);
684745
}
685746

686747
break;

src/test/ui/const-generics/const-arg-type-arg-misordered.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ LL | fn foo<const N: usize>() -> Array<N, ()> {
1414
| ^
1515
|
1616
= note: type arguments must be provided before constant arguments
17+
= help: reorder the arguments: types, then consts: `<T, N>`
1718

1819
error: aborting due to previous error; 1 warning emitted
1920

src/test/ui/suggestions/suggest-move-types.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=()
125125
| ^^
126126
|
127127
= note: lifetime arguments must be provided before type arguments
128+
= help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
128129

129130
error[E0747]: lifetime provided when a type was expected
130131
--> $DIR/suggest-move-types.rs:82:56
@@ -133,6 +134,7 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, '
133134
| ^^
134135
|
135136
= note: lifetime arguments must be provided before type arguments
137+
= help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
136138

137139
error: aborting due to 12 previous errors
138140

0 commit comments

Comments
 (0)