Skip to content

Commit b53a1b3

Browse files
committed
make adt_const_params feature suggestion more consistent with others and only suggest it when the type can probably work
1 parent 1393ef1 commit b53a1b3

40 files changed

+254
-84
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+57-32
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ use rustc_span::symbol::{sym, Ident, Symbol};
2424
use rustc_span::{Span, DUMMY_SP};
2525
use rustc_target::spec::abi::Abi;
2626
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
27+
use rustc_trait_selection::traits::misc::{
28+
type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError,
29+
};
2730
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
2831
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
2932
use rustc_trait_selection::traits::{
@@ -865,43 +868,65 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
865868
);
866869
});
867870
} else {
868-
let err_ty_str;
869-
let mut is_ptr = true;
870-
871-
let err = match ty.kind() {
871+
let diag = match ty.kind() {
872872
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
873-
ty::FnPtr(_) => Some("function pointers"),
874-
ty::RawPtr(_) => Some("raw pointers"),
875-
_ => {
876-
is_ptr = false;
877-
err_ty_str = format!("`{ty}`");
878-
Some(err_ty_str.as_str())
879-
}
873+
ty::FnPtr(_) => Some(tcx.sess.struct_span_err(
874+
hir_ty.span,
875+
"using function pointers as const generic parameters is forbidden",
876+
)),
877+
ty::RawPtr(_) => Some(tcx.sess.struct_span_err(
878+
hir_ty.span,
879+
"using raw pointers as const generic parameters is forbidden",
880+
)),
881+
_ => Some(tcx.sess.struct_span_err(
882+
hir_ty.span,
883+
format!("`{}` is forbidden as the type of a const generic parameter", ty),
884+
)),
880885
};
881886

882-
if let Some(unsupported_type) = err {
883-
if is_ptr {
884-
tcx.sess.span_err(
885-
hir_ty.span,
886-
format!(
887-
"using {unsupported_type} as const generic parameters is forbidden",
888-
),
889-
);
890-
} else {
891-
let mut err = tcx.sess.struct_span_err(
892-
hir_ty.span,
893-
format!(
894-
"{unsupported_type} is forbidden as the type of a const generic parameter",
895-
),
896-
);
897-
err.note("the only supported types are integers, `bool` and `char`");
898-
if tcx.sess.is_nightly_build() {
899-
err.help(
900-
"more complex types are supported with `#![feature(adt_const_params)]`",
901-
);
887+
if let Some(mut diag) = diag {
888+
diag.note("the only supported types are integers, `bool` and `char`");
889+
890+
let cause = ObligationCause::misc(hir_ty.span, param.def_id);
891+
let may_suggest_feature = match type_allowed_to_implement_const_param_ty(
892+
tcx,
893+
tcx.param_env(param.def_id),
894+
ty,
895+
cause,
896+
) {
897+
// Can never implement `ConstParamTy`, don't suggest anything.
898+
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false,
899+
// May be able to implement `ConstParamTy`. Only emit the feature help
900+
// if the type is local, since the user may be able to fix the local type.
901+
Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
902+
fn ty_is_local(ty: Ty<'_>) -> bool {
903+
match ty.kind() {
904+
ty::Adt(adt_def, ..) => adt_def.did().is_local(),
905+
// Arrays and slices use the inner type's `ConstParamTy`.
906+
ty::Array(ty, ..) => ty_is_local(*ty),
907+
ty::Slice(ty) => ty_is_local(*ty),
908+
// `&` references use the inner type's `ConstParamTy`.
909+
// `&mut` are not supported.
910+
ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty),
911+
// Say that a tuple is local if any of its components are local.
912+
// This is not strictly correct, but it's likely that the user can fix the local component.
913+
ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)),
914+
_ => false,
915+
}
916+
}
917+
918+
ty_is_local(ty)
902919
}
903-
err.emit();
920+
// Implments `ConstParamTy`, suggest adding the feature to enable.
921+
Ok(..) => true,
922+
};
923+
if may_suggest_feature && tcx.sess.is_nightly_build() {
924+
diag.help(
925+
"add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types",
926+
);
904927
}
928+
929+
diag.emit();
905930
}
906931
}
907932
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Test that when adt_const_params is not enabled, we suggest adding the feature only when
2+
// it would be possible for the type to be used as a const generic or when it's likely
3+
// possible for the user to fix their type to be used.
4+
5+
// Can never be used as const generics.
6+
fn uwu_0<const N: &'static mut ()>() {}
7+
//~^ ERROR: forbidden as the type of a const generic
8+
9+
// Needs the feature but can be used, so suggest adding the feature.
10+
fn owo_0<const N: &'static u32>() {}
11+
//~^ ERROR: forbidden as the type of a const generic
12+
//~^^ HELP: add `#![feature(adt_const_params)]`
13+
14+
// Can only be used in const generics with changes.
15+
struct Meow {
16+
meow: u8,
17+
}
18+
19+
fn meow_0<const N: Meow>() {}
20+
//~^ ERROR: forbidden as the type of a const generic
21+
//~^^ HELP: add `#![feature(adt_const_params)]`
22+
fn meow_1<const N: &'static Meow>() {}
23+
//~^ ERROR: forbidden as the type of a const generic
24+
//~^^ HELP: add `#![feature(adt_const_params)]`
25+
fn meow_2<const N: [Meow; 100]>() {}
26+
//~^ ERROR: forbidden as the type of a const generic
27+
//~^^ HELP: add `#![feature(adt_const_params)]`
28+
fn meow_3<const N: (Meow, u8)>() {}
29+
//~^ ERROR: forbidden as the type of a const generic
30+
//~^^ HELP: add `#![feature(adt_const_params)]`
31+
32+
// This is suboptimal that it thinks it can be used
33+
// but better to suggest the feature to the user.
34+
fn meow_4<const N: (Meow, String)>() {}
35+
//~^ ERROR: forbidden as the type of a const generic
36+
//~^^ HELP: add `#![feature(adt_const_params)]`
37+
38+
// Non-local ADT that does not impl `ConstParamTy`
39+
fn nya_0<const N: String>() {}
40+
//~^ ERROR: forbidden as the type of a const generic
41+
fn nya_1<const N: Vec<u32>>() {}
42+
//~^ ERROR: forbidden as the type of a const generic
43+
44+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
error: `&'static mut ()` is forbidden as the type of a const generic parameter
2+
--> $DIR/suggest_feature_only_when_possible.rs:6:19
3+
|
4+
LL | fn uwu_0<const N: &'static mut ()>() {}
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: the only supported types are integers, `bool` and `char`
8+
9+
error: `&'static u32` is forbidden as the type of a const generic parameter
10+
--> $DIR/suggest_feature_only_when_possible.rs:10:19
11+
|
12+
LL | fn owo_0<const N: &'static u32>() {}
13+
| ^^^^^^^^^^^^
14+
|
15+
= note: the only supported types are integers, `bool` and `char`
16+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
17+
18+
error: `Meow` is forbidden as the type of a const generic parameter
19+
--> $DIR/suggest_feature_only_when_possible.rs:19:20
20+
|
21+
LL | fn meow_0<const N: Meow>() {}
22+
| ^^^^
23+
|
24+
= note: the only supported types are integers, `bool` and `char`
25+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
26+
27+
error: `&'static Meow` is forbidden as the type of a const generic parameter
28+
--> $DIR/suggest_feature_only_when_possible.rs:22:20
29+
|
30+
LL | fn meow_1<const N: &'static Meow>() {}
31+
| ^^^^^^^^^^^^^
32+
|
33+
= note: the only supported types are integers, `bool` and `char`
34+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
35+
36+
error: `[Meow; 100]` is forbidden as the type of a const generic parameter
37+
--> $DIR/suggest_feature_only_when_possible.rs:25:20
38+
|
39+
LL | fn meow_2<const N: [Meow; 100]>() {}
40+
| ^^^^^^^^^^^
41+
|
42+
= note: the only supported types are integers, `bool` and `char`
43+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
44+
45+
error: `(Meow, u8)` is forbidden as the type of a const generic parameter
46+
--> $DIR/suggest_feature_only_when_possible.rs:28:20
47+
|
48+
LL | fn meow_3<const N: (Meow, u8)>() {}
49+
| ^^^^^^^^^^
50+
|
51+
= note: the only supported types are integers, `bool` and `char`
52+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
53+
54+
error: `(Meow, String)` is forbidden as the type of a const generic parameter
55+
--> $DIR/suggest_feature_only_when_possible.rs:34:20
56+
|
57+
LL | fn meow_4<const N: (Meow, String)>() {}
58+
| ^^^^^^^^^^^^^^
59+
|
60+
= note: the only supported types are integers, `bool` and `char`
61+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
62+
63+
error: `String` is forbidden as the type of a const generic parameter
64+
--> $DIR/suggest_feature_only_when_possible.rs:39:19
65+
|
66+
LL | fn nya_0<const N: String>() {}
67+
| ^^^^^^
68+
|
69+
= note: the only supported types are integers, `bool` and `char`
70+
71+
error: `Vec<u32>` is forbidden as the type of a const generic parameter
72+
--> $DIR/suggest_feature_only_when_possible.rs:41:19
73+
|
74+
LL | fn nya_1<const N: Vec<u32>>() {}
75+
| ^^^^^^^^
76+
|
77+
= note: the only supported types are integers, `bool` and `char`
78+
79+
error: aborting due to 9 previous errors
80+

tests/ui/const-generics/const-param-elided-lifetime.min.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ LL | struct A<const N: &u8>;
3535
| ^^^
3636
|
3737
= note: the only supported types are integers, `bool` and `char`
38-
= help: more complex types are supported with `#![feature(adt_const_params)]`
38+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
3939

4040
error: `&u8` is forbidden as the type of a const generic parameter
4141
--> $DIR/const-param-elided-lifetime.rs:14:15
@@ -44,7 +44,7 @@ LL | impl<const N: &u8> A<N> {
4444
| ^^^
4545
|
4646
= note: the only supported types are integers, `bool` and `char`
47-
= help: more complex types are supported with `#![feature(adt_const_params)]`
47+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
4848

4949
error: `&u8` is forbidden as the type of a const generic parameter
5050
--> $DIR/const-param-elided-lifetime.rs:22:15
@@ -53,7 +53,7 @@ LL | impl<const N: &u8> B for A<N> {}
5353
| ^^^
5454
|
5555
= note: the only supported types are integers, `bool` and `char`
56-
= help: more complex types are supported with `#![feature(adt_const_params)]`
56+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
5757

5858
error: `&u8` is forbidden as the type of a const generic parameter
5959
--> $DIR/const-param-elided-lifetime.rs:26:17
@@ -62,7 +62,7 @@ LL | fn bar<const N: &u8>() {}
6262
| ^^^
6363
|
6464
= note: the only supported types are integers, `bool` and `char`
65-
= help: more complex types are supported with `#![feature(adt_const_params)]`
65+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
6666

6767
error: `&u8` is forbidden as the type of a const generic parameter
6868
--> $DIR/const-param-elided-lifetime.rs:17:21
@@ -71,7 +71,7 @@ LL | fn foo<const M: &u8>(&self) {}
7171
| ^^^
7272
|
7373
= note: the only supported types are integers, `bool` and `char`
74-
= help: more complex types are supported with `#![feature(adt_const_params)]`
74+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
7575

7676
error: aborting due to 10 previous errors
7777

tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
2121
| ^^^^^^^
2222
|
2323
= note: the only supported types are integers, `bool` and `char`
24-
= help: more complex types are supported with `#![feature(adt_const_params)]`
24+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
2525

2626
error: `[u8; N]` is forbidden as the type of a const generic parameter
2727
--> $DIR/const-param-type-depends-on-const-param.rs:15:35
@@ -30,7 +30,7 @@ LL | pub struct SelfDependent<const N: [u8; N]>;
3030
| ^^^^^^^
3131
|
3232
= note: the only supported types are integers, `bool` and `char`
33-
= help: more complex types are supported with `#![feature(adt_const_params)]`
33+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
3434

3535
error: aborting due to 4 previous errors
3636

tests/ui/const-generics/float-generic.simple.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ LL | fn foo<const F: f32>() {}
55
| ^^^
66
|
77
= note: the only supported types are integers, `bool` and `char`
8-
= help: more complex types are supported with `#![feature(adt_const_params)]`
98

109
error: aborting due to previous error
1110

tests/ui/const-generics/fn-const-param-call.min.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ error: using function pointers as const generic parameters is forbidden
33
|
44
LL | struct Wrapper<const F: fn() -> u32>;
55
| ^^^^^^^^^^^
6+
|
7+
= note: the only supported types are integers, `bool` and `char`
68

79
error: using function pointers as const generic parameters is forbidden
810
--> $DIR/fn-const-param-call.rs:13:15
911
|
1012
LL | impl<const F: fn() -> u32> Wrapper<F> {
1113
| ^^^^^^^^^^^
14+
|
15+
= note: the only supported types are integers, `bool` and `char`
1216

1317
error: aborting due to 2 previous errors
1418

tests/ui/const-generics/fn-const-param-infer.min.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error: using function pointers as const generic parameters is forbidden
33
|
44
LL | struct Checked<const F: fn(usize) -> bool>;
55
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: the only supported types are integers, `bool` and `char`
68

79
error: aborting due to previous error
810

tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ LL | struct B<const CFG: Config> {
2323
| ^^^^^^
2424
|
2525
= note: the only supported types are integers, `bool` and `char`
26-
= help: more complex types are supported with `#![feature(adt_const_params)]`
26+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
2727

2828
error: aborting due to 3 previous errors
2929

tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ LL | trait Trait<const S: &'static str> {}
1414
| ^^^^^^^^^^^^
1515
|
1616
= note: the only supported types are integers, `bool` and `char`
17-
= help: more complex types are supported with `#![feature(adt_const_params)]`
17+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
1818

1919
error: aborting due to 2 previous errors
2020

tests/ui/const-generics/issues/issue-56445-1.min.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
1313
| ^^^^^^^
1414
|
1515
= note: the only supported types are integers, `bool` and `char`
16-
= help: more complex types are supported with `#![feature(adt_const_params)]`
16+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
1717

1818
error: aborting due to 2 previous errors
1919

tests/ui/const-generics/issues/issue-62878.min.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ LL | fn foo<const N: usize, const A: [u8; N]>() {}
1313
| ^^^^^^^
1414
|
1515
= note: the only supported types are integers, `bool` and `char`
16-
= help: more complex types are supported with `#![feature(adt_const_params)]`
16+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
1717

1818
error: aborting due to 2 previous errors
1919

tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | fn test<const T: &'static dyn A>() {
55
| ^^^^^^^^^^^^^^
66
|
77
= note: the only supported types are integers, `bool` and `char`
8-
= help: more complex types are supported with `#![feature(adt_const_params)]`
8+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
99

1010
error: aborting due to previous error
1111

tests/ui/const-generics/issues/issue-68615-adt.min.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | struct Const<const V: [usize; 0]> {}
55
| ^^^^^^^^^^
66
|
77
= note: the only supported types are integers, `bool` and `char`
8-
= help: more complex types are supported with `#![feature(adt_const_params)]`
8+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
99

1010
error: aborting due to previous error
1111

tests/ui/const-generics/issues/issue-68615-array.min.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | struct Foo<const V: [usize; 0] > {}
55
| ^^^^^^^^^^
66
|
77
= note: the only supported types are integers, `bool` and `char`
8-
= help: more complex types are supported with `#![feature(adt_const_params)]`
8+
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
99

1010
error: aborting due to previous error
1111

0 commit comments

Comments
 (0)