Skip to content

Commit be2a3f8

Browse files
authored
Rollup merge of rust-lang#80538 - JulianKnodt:err_usize, r=lcnr
Add check for `[T;N]`/`usize` mismatch in astconv Helps clarify the issue in rust-lang#80506 by adding a specific check for mismatches between [T;N] and usize. r? `@lcnr`
2 parents 4c4e8e7 + 54883e0 commit be2a3f8

File tree

7 files changed

+95
-41
lines changed

7 files changed

+95
-41
lines changed

Diff for: Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3745,6 +3745,7 @@ version = "0.0.0"
37453745
dependencies = [
37463746
"rustc_ast",
37473747
"rustc_data_structures",
3748+
"rustc_feature",
37483749
"rustc_index",
37493750
"rustc_macros",
37503751
"rustc_serialize",

Diff for: compiler/rustc_hir/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ doctest = false
99

1010
[dependencies]
1111
rustc_target = { path = "../rustc_target" }
12+
rustc_feature = { path = "../rustc_feature" }
1213
rustc_macros = { path = "../rustc_macros" }
1314
rustc_data_structures = { path = "../rustc_data_structures" }
1415
rustc_index = { path = "../rustc_index" }

Diff for: compiler/rustc_hir/src/hir.rs

+8
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,14 @@ impl GenericArg<'_> {
290290
GenericArg::Const(_) => "const",
291291
}
292292
}
293+
294+
pub fn to_ord(&self, feats: &rustc_feature::Features) -> ast::ParamKindOrd {
295+
match self {
296+
GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime,
297+
GenericArg::Type(_) => ast::ParamKindOrd::Type,
298+
GenericArg::Const(_) => ast::ParamKindOrd::Const { unordered: feats.const_generics },
299+
}
300+
}
293301
}
294302

295303
#[derive(Debug, HashStable_Generic)]

Diff for: compiler/rustc_middle/src/ty/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,15 @@ impl GenericParamDefKind {
801801
GenericParamDefKind::Const => "constant",
802802
}
803803
}
804+
pub fn to_ord(&self, tcx: TyCtxt<'_>) -> ast::ParamKindOrd {
805+
match self {
806+
GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
807+
GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
808+
GenericParamDefKind::Const => {
809+
ast::ParamKindOrd::Const { unordered: tcx.features().const_generics }
810+
}
811+
}
812+
}
804813
}
805814

806815
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]

Diff for: compiler/rustc_typeck/src/astconv/generics.rs

+51-41
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_hir::GenericArg;
1111
use rustc_middle::ty::{
1212
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
1313
};
14-
use rustc_session::{lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, Session};
14+
use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
1515
use rustc_span::{symbol::kw, MultiSpan, Span};
1616

1717
use smallvec::SmallVec;
@@ -20,62 +20,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2020
/// Report an error that a generic argument did not match the generic parameter that was
2121
/// expected.
2222
fn generic_arg_mismatch_err(
23-
sess: &Session,
23+
tcx: TyCtxt<'_>,
2424
arg: &GenericArg<'_>,
25-
kind: &'static str,
25+
param: &GenericParamDef,
2626
possible_ordering_error: bool,
2727
help: Option<&str>,
2828
) {
29+
let sess = tcx.sess;
2930
let mut err = struct_span_err!(
3031
sess,
3132
arg.span(),
3233
E0747,
3334
"{} provided when a {} was expected",
3435
arg.descr(),
35-
kind,
36+
param.kind.descr(),
3637
);
3738

38-
let unordered = sess.features_untracked().const_generics;
39-
let kind_ord = match kind {
40-
"lifetime" => ParamKindOrd::Lifetime,
41-
"type" => ParamKindOrd::Type,
42-
"constant" => ParamKindOrd::Const { unordered },
43-
// It's more concise to match on the string representation, though it means
44-
// the match is non-exhaustive.
45-
_ => bug!("invalid generic parameter kind {}", kind),
46-
};
47-
48-
if let ParamKindOrd::Const { .. } = kind_ord {
39+
if let GenericParamDefKind::Const { .. } = param.kind {
4940
if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg {
5041
err.help("const arguments cannot yet be inferred with `_`");
5142
}
5243
}
5344

54-
let arg_ord = match arg {
55-
GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
56-
GenericArg::Type(_) => ParamKindOrd::Type,
57-
GenericArg::Const(_) => ParamKindOrd::Const { unordered },
58-
};
59-
60-
if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }))
61-
&& matches!(kind_ord, ParamKindOrd::Const { .. })
62-
{
63-
let suggestions = vec![
64-
(arg.span().shrink_to_lo(), String::from("{ ")),
65-
(arg.span().shrink_to_hi(), String::from(" }")),
66-
];
67-
err.multipart_suggestion(
68-
"if this generic argument was intended as a const parameter, \
45+
// Specific suggestion set for diagnostics
46+
match (arg, &param.kind) {
47+
(
48+
GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }),
49+
GenericParamDefKind::Const { .. },
50+
) => {
51+
let suggestions = vec![
52+
(arg.span().shrink_to_lo(), String::from("{ ")),
53+
(arg.span().shrink_to_hi(), String::from(" }")),
54+
];
55+
err.multipart_suggestion(
56+
"if this generic argument was intended as a const parameter, \
6957
try surrounding it with braces:",
70-
suggestions,
71-
Applicability::MaybeIncorrect,
72-
);
58+
suggestions,
59+
Applicability::MaybeIncorrect,
60+
);
61+
}
62+
(
63+
GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
64+
GenericParamDefKind::Const { .. },
65+
) if tcx.type_of(param.def_id) == tcx.types.usize => {
66+
let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id));
67+
if let Ok(snippet) = snippet {
68+
err.span_suggestion(
69+
arg.span(),
70+
"array type provided where a `usize` was expected, try",
71+
format!("{{ {} }}", snippet),
72+
Applicability::MaybeIncorrect,
73+
);
74+
}
75+
}
76+
_ => {}
7377
}
7478

79+
let kind_ord = param.kind.to_ord(tcx);
80+
let arg_ord = arg.to_ord(&tcx.features());
81+
7582
// This note is only true when generic parameters are strictly ordered by their kind.
7683
if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
77-
let (first, last) =
78-
if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
84+
let (first, last) = if kind_ord < arg_ord {
85+
(param.kind.descr(), arg.descr())
86+
} else {
87+
(arg.descr(), param.kind.descr())
88+
};
7989
err.note(&format!("{} arguments must be provided before {} arguments", first, last));
8090
if let Some(help) = help {
8191
err.help(help);
@@ -203,7 +213,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
203213
// We expected a lifetime argument, but got a type or const
204214
// argument. That means we're inferring the lifetimes.
205215
substs.push(ctx.inferred_kind(None, param, infer_args));
206-
force_infer_lt = Some(arg);
216+
force_infer_lt = Some((arg, param));
207217
params.next();
208218
}
209219
(GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => {
@@ -213,7 +223,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
213223
// ignore it.
214224
args.next();
215225
}
216-
(_, kind, _) => {
226+
(_, _, _) => {
217227
// We expected one kind of parameter, but the user provided
218228
// another. This is an error. However, if we already know that
219229
// the arguments don't match up with the parameters, we won't issue
@@ -256,9 +266,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
256266
param_types_present.dedup();
257267

258268
Self::generic_arg_mismatch_err(
259-
tcx.sess,
269+
tcx,
260270
arg,
261-
kind.descr(),
271+
param,
262272
!args_iter.clone().is_sorted_by_key(|arg| match arg {
263273
GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
264274
GenericArg::Type(_) => ParamKindOrd::Type,
@@ -315,9 +325,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
315325
{
316326
let kind = arg.descr();
317327
assert_eq!(kind, "lifetime");
318-
let provided =
328+
let (provided_arg, param) =
319329
force_infer_lt.expect("lifetimes ought to have been inferred");
320-
Self::generic_arg_mismatch_err(tcx.sess, provided, kind, false, None);
330+
Self::generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
321331
}
322332

323333
break;
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![crate_type = "lib"]
2+
3+
fn example<const N: usize>() {}
4+
5+
fn other() {
6+
example::<[usize; 3]>();
7+
//~^ ERROR type provided when a const
8+
example::<[usize; 4+5]>();
9+
//~^ ERROR type provided when a const
10+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0747]: type provided when a constant was expected
2+
--> $DIR/suggest_const_for_array.rs:6:13
3+
|
4+
LL | example::<[usize; 3]>();
5+
| ^^^^^^^^^^ help: array type provided where a `usize` was expected, try: `{ 3 }`
6+
7+
error[E0747]: type provided when a constant was expected
8+
--> $DIR/suggest_const_for_array.rs:8:13
9+
|
10+
LL | example::<[usize; 4+5]>();
11+
| ^^^^^^^^^^^^ help: array type provided where a `usize` was expected, try: `{ 4+5 }`
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0747`.

0 commit comments

Comments
 (0)