Skip to content

Commit

Permalink
make adt_const_params feature suggestion more consistent with others …
Browse files Browse the repository at this point in the history
…and only suggest it when the type can probably work
  • Loading branch information
asquared31415 committed Sep 28, 2023
1 parent 1393ef1 commit 2a15beb
Show file tree
Hide file tree
Showing 40 changed files with 254 additions and 84 deletions.
89 changes: 57 additions & 32 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::misc::{
type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError,
};
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
Expand Down Expand Up @@ -865,43 +868,65 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
);
});
} else {
let err_ty_str;
let mut is_ptr = true;

let err = match ty.kind() {
let diag = match ty.kind() {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => {
is_ptr = false;
err_ty_str = format!("`{ty}`");
Some(err_ty_str.as_str())
}
ty::FnPtr(_) => Some(tcx.sess.struct_span_err(
hir_ty.span,
"using function pointers as const generic parameters is forbidden",
)),
ty::RawPtr(_) => Some(tcx.sess.struct_span_err(
hir_ty.span,
"using raw pointers as const generic parameters is forbidden",
)),
_ => Some(tcx.sess.struct_span_err(
hir_ty.span,
format!("`{}` is forbidden as the type of a const generic parameter", ty),
)),
};

if let Some(unsupported_type) = err {
if is_ptr {
tcx.sess.span_err(
hir_ty.span,
format!(
"using {unsupported_type} as const generic parameters is forbidden",
),
);
} else {
let mut err = tcx.sess.struct_span_err(
hir_ty.span,
format!(
"{unsupported_type} is forbidden as the type of a const generic parameter",
),
);
err.note("the only supported types are integers, `bool` and `char`");
if tcx.sess.is_nightly_build() {
err.help(
"more complex types are supported with `#![feature(adt_const_params)]`",
if let Some(mut diag) = diag {
diag.note("the only supported types are integers, `bool` and `char`");

let cause = ObligationCause::misc(hir_ty.span, param.def_id);
let may_suggest_feature = match type_allowed_to_implement_const_param_ty(
tcx,
tcx.param_env(param.def_id),
ty,
cause,
) {
// Can never implement `ConstParamTy`, don't suggest anything.
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false,
// May be able to implement `ConstParamTy`. Only emit the feature help
// if the type is local, since the user may be able to fix the local type.
Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
fn ty_is_local(ty: Ty<'_>) -> bool {
match ty.kind() {
ty::Adt(adt_def, ..) => adt_def.did().is_local(),
// Arrays and slices use the inner type's `ConstParamTy`.
ty::Array(ty, ..) => ty_is_local(*ty),
ty::Slice(ty) => ty_is_local(*ty),
// `&` references use the inner type's `ConstParamTy`.
// `&mut` are not supported.
ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty),
// Say that a tuple is local if any of its components are local.
// This is not strictly correct, but it's likely that the user can fix the local component.
ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)),
_ => false,
}
}

ty_is_local(ty)
},
// Implments `ConstParamTy`, suggest adding the feature to enable.
Ok(..) => true,
};
if may_suggest_feature && tcx.sess.is_nightly_build() {
diag.help(
"add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types",
);
}
err.emit();
}

diag.emit();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Test that when adt_const_params is not enabled, we suggest adding the feature only when
// it would be possible for the type to be used as a const generic or when it's likely
// possible for the user to fix their type to be used.

// Can never be used as const generics.
fn uwu_0<const N: &'static mut ()>() {}
//~^ ERROR: forbidden as the type of a const generic

// Needs the feature but can be used, so suggest adding the feature.
fn owo_0<const N: &'static u32>() {}
//~^ ERROR: forbidden as the type of a const generic
//~^^ HELP: add `#![feature(adt_const_params)]`

// Can only be used in const generics with changes.
struct Meow {
meow: u8,
}

fn meow_0<const N: Meow>() {}
//~^ ERROR: forbidden as the type of a const generic
//~^^ HELP: add `#![feature(adt_const_params)]`
fn meow_1<const N: &'static Meow>() {}
//~^ ERROR: forbidden as the type of a const generic
//~^^ HELP: add `#![feature(adt_const_params)]`
fn meow_2<const N: [Meow; 100]>() {}
//~^ ERROR: forbidden as the type of a const generic
//~^^ HELP: add `#![feature(adt_const_params)]`
fn meow_3<const N: (Meow, u8)>() {}
//~^ ERROR: forbidden as the type of a const generic
//~^^ HELP: add `#![feature(adt_const_params)]`

// This is suboptimal that it thinks it can be used
// but better to suggest the feature to the user.
fn meow_4<const N: (Meow, String)>() {}
//~^ ERROR: forbidden as the type of a const generic
//~^^ HELP: add `#![feature(adt_const_params)]`

// Non-local ADT that does not impl `ConstParamTy`
fn nya_0<const N: String>() {}
//~^ ERROR: forbidden as the type of a const generic
fn nya_1<const N: Vec<u32>>() {}
//~^ ERROR: forbidden as the type of a const generic

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
error: `&'static mut ()` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:6:19
|
LL | fn uwu_0<const N: &'static mut ()>() {}
| ^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`

error: `&'static u32` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:10:19
|
LL | fn owo_0<const N: &'static u32>() {}
| ^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: `Meow` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:19:20
|
LL | fn meow_0<const N: Meow>() {}
| ^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: `&'static Meow` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:22:20
|
LL | fn meow_1<const N: &'static Meow>() {}
| ^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: `[Meow; 100]` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:25:20
|
LL | fn meow_2<const N: [Meow; 100]>() {}
| ^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: `(Meow, u8)` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:28:20
|
LL | fn meow_3<const N: (Meow, u8)>() {}
| ^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: `(Meow, String)` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:34:20
|
LL | fn meow_4<const N: (Meow, String)>() {}
| ^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: `String` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:39:19
|
LL | fn nya_0<const N: String>() {}
| ^^^^^^
|
= note: the only supported types are integers, `bool` and `char`

error: `Vec<u32>` is forbidden as the type of a const generic parameter
--> $DIR/suggest_feature_only_when_possible.rs:41:19
|
LL | fn nya_1<const N: Vec<u32>>() {}
| ^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`

error: aborting due to 9 previous errors

10 changes: 5 additions & 5 deletions tests/ui/const-generics/const-param-elided-lifetime.min.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ LL | struct A<const N: &u8>;
| ^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(adt_const_params)]`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

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

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

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

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

error: aborting due to 10 previous errors

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

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

error: aborting due to 4 previous errors

Expand Down
1 change: 0 additions & 1 deletion tests/ui/const-generics/float-generic.simple.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ LL | fn foo<const F: f32>() {}
| ^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(adt_const_params)]`

error: aborting due to previous error

4 changes: 4 additions & 0 deletions tests/ui/const-generics/fn-const-param-call.min.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ error: using function pointers as const generic parameters is forbidden
|
LL | struct Wrapper<const F: fn() -> u32>;
| ^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`

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

error: aborting due to 2 previous errors

2 changes: 2 additions & 0 deletions tests/ui/const-generics/fn-const-param-infer.min.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ error: using function pointers as const generic parameters is forbidden
|
LL | struct Checked<const F: fn(usize) -> bool>;
| ^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`

error: aborting due to previous error

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

error: aborting due to 3 previous errors

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

error: aborting due to 2 previous errors

2 changes: 1 addition & 1 deletion tests/ui/const-generics/issues/issue-56445-1.min.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
| ^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(adt_const_params)]`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: aborting due to 2 previous errors

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/const-generics/issues/issue-62878.min.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LL | fn foo<const N: usize, const A: [u8; N]>() {}
| ^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(adt_const_params)]`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: aborting due to 2 previous errors

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

error: aborting due to previous error

2 changes: 1 addition & 1 deletion tests/ui/const-generics/issues/issue-68615-adt.min.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | struct Const<const V: [usize; 0]> {}
| ^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(adt_const_params)]`
= help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types

error: aborting due to previous error

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

error: aborting due to previous error

Loading

0 comments on commit 2a15beb

Please sign in to comment.