Skip to content

Commit

Permalink
Rollup merge of rust-lang#122802 - estebank:unconstrained-generic-con…
Browse files Browse the repository at this point in the history
…st, r=Nadrieril

Provide structured suggestion for unconstrained generic constant

```
error: unconstrained generic constant
  --> $DIR/const-argument-if-length.rs:18:10
   |
LL |     pad: [u8; is_zst::<T>()],
   |          ^^^^^^^^^^^^^^^^^^^
   |
help: try adding a `where` bound
   |
LL | pub struct AtLeastByte<T: ?Sized> where [(); is_zst::<T>()]: {
   |                                   ++++++++++++++++++++++++++
```

Detect when the constant expression isn't `usize` and suggest casting:

```
error: unconstrained generic constant
 --> f300.rs:6:10
  |
6 |     bb::<{!N}>();
  |          ^^^^
-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs:3539:36
  |
help: try adding a `where` bound
  |
5 | fn b<const N: bool>() where [(); {!N} as usize]: {
  |                       ++++++++++++++++++++++++++
```

Fix rust-lang#122395.
  • Loading branch information
matthiaskrgr committed Mar 25, 2024
2 parents eab1377 + 6b24fdf commit 449db0e
Show file tree
Hide file tree
Showing 41 changed files with 351 additions and 111 deletions.
Expand Up @@ -3536,12 +3536,39 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut err =
self.dcx().struct_span_err(span, "unconstrained generic constant");
let const_span = self.tcx.def_span(uv.def);

let const_ty = self.tcx.type_of(uv.def).instantiate(self.tcx, uv.args);
let cast = if const_ty != self.tcx.types.usize { " as usize" } else { "" };
let msg = "try adding a `where` bound";
match self.tcx.sess.source_map().span_to_snippet(const_span) {
Ok(snippet) => err.help(format!(
"try adding a `where` bound using this expression: `where [(); {snippet}]:`"
)),
_ => err.help("consider adding a `where` bound using this expression"),
};
Ok(snippet) => {
let code = format!("[(); {snippet}{cast}]:");
let def_id = if let ObligationCauseCode::CompareImplItemObligation {
trait_item_def_id,
..
} = obligation.cause.code()
{
trait_item_def_id.as_local()
} else {
Some(obligation.cause.body_id)
};
if let Some(def_id) = def_id
&& let Some(generics) = self.tcx.hir().get_generics(def_id)
{
err.span_suggestion_verbose(
generics.tail_span_for_predicate_suggestion(),
msg,
format!("{} {code}", generics.add_where_or_trailing_comma()),
Applicability::MaybeIncorrect,
);
} else {
err.help(format!("{msg}: where {code}"));
};
}
_ => {
err.help(msg);
}
};
Ok(err)
}
ty::ConstKind::Expr(_) => {
Expand Down
5 changes: 4 additions & 1 deletion tests/ui/const-generics/const-argument-if-length.full.stderr
Expand Up @@ -4,7 +4,10 @@ error: unconstrained generic constant
LL | pad: [u8; is_zst::<T>()],
| ^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); is_zst::<T>()]:`
help: try adding a `where` bound
|
LL | pub struct AtLeastByte<T: ?Sized> where [(); is_zst::<T>()]: {
| ++++++++++++++++++++++++++

error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/const-argument-if-length.rs:16:12
Expand Down
10 changes: 8 additions & 2 deletions tests/ui/const-generics/defaults/generic-expr-default.stderr
Expand Up @@ -4,15 +4,21 @@ error: unconstrained generic constant
LL | pub fn needs_evaluatable_bound<const N1: usize>() -> Foo<N1> {
| ^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:`
help: try adding a `where` bound
|
LL | pub fn needs_evaluatable_bound<const N1: usize>() -> Foo<N1> where [(); { N + 1 }]: {
| ++++++++++++++++++++++

error: unconstrained generic constant
--> $DIR/generic-expr-default.rs:14:58
|
LL | fn needs_evaluatable_bound_alias<T, const N: usize>() -> FooAlias<N>
| ^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:`
help: try adding a `where` bound
|
LL | fn needs_evaluatable_bound_alias<T, const N: usize>() -> FooAlias<N> where [(); { N + 1 }]:
| ++++++++++++++++++++++

error: aborting due to 2 previous errors

5 changes: 4 additions & 1 deletion tests/ui/const-generics/ensure_is_evaluatable.stderr
Expand Up @@ -4,7 +4,6 @@ error: unconstrained generic constant
LL | bar()
| ^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); N + 1]:`
note: required by a bound in `bar`
--> $DIR/ensure_is_evaluatable.rs:15:10
|
Expand All @@ -13,6 +12,10 @@ LL | fn bar<const N: usize>() -> [(); N]
LL | where
LL | [(); N + 1]:,
| ^^^^^ required by this bound in `bar`
help: try adding a `where` bound
|
LL | [(); M + 1]:, [(); N + 1]:
| ~~~~~~~~~~~~~~

error: aborting due to 1 previous error

5 changes: 4 additions & 1 deletion tests/ui/const-generics/fn_with_two_const_inputs.stderr
Expand Up @@ -4,7 +4,6 @@ error: unconstrained generic constant
LL | bar()
| ^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); N + 1]:`
note: required by a bound in `bar`
--> $DIR/fn_with_two_const_inputs.rs:18:10
|
Expand All @@ -13,6 +12,10 @@ LL | fn bar<const N: usize>() -> [(); N]
LL | where
LL | [(); N + 1]:,
| ^^^^^ required by this bound in `bar`
help: try adding a `where` bound
|
LL | [(); both(N + 1, M + 1)]:, [(); N + 1]:
| ~~~~~~~~~~~~~~

error: aborting due to 1 previous error

@@ -0,0 +1,21 @@
//@ run-rustfix
#![feature(generic_const_exprs)]
#![allow(incomplete_features, dead_code)]

struct Evaluatable<const N: u128> {}

struct Foo<const N: u8>([u8; N as usize])
//~^ ERROR unconstrained generic constant
where
Evaluatable<{N as u128}>:, [(); N as usize]:;
//~^ HELP try adding a `where` bound

struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:, [(); {N as u128} as usize]:;
//~^ ERROR unconstrained generic constant
//~| HELP try adding a `where` bound

struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:, [(); (N + 2) as usize]:;
//~^ ERROR unconstrained generic constant
//~| HELP try adding a `where` bound

fn main() {}
@@ -1,20 +1,21 @@
//@ run-rustfix
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
#![allow(incomplete_features, dead_code)]

struct Evaluatable<const N: u128> {}

struct Foo<const N: u8>([u8; N as usize])
//~^ Error: unconstrained generic constant
//~| help: try adding a `where` bound using this expression: `where [(); N as usize]:`
//~^ ERROR unconstrained generic constant
where
Evaluatable<{N as u128}>:;
//~^ HELP try adding a `where` bound

struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
//~^ Error: unconstrained generic constant
//~| help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
//~^ ERROR unconstrained generic constant
//~| HELP try adding a `where` bound

struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
//~^ Error: unconstrained generic constant
//~| help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
//~^ ERROR unconstrained generic constant
//~| HELP try adding a `where` bound

fn main() {}
@@ -1,26 +1,35 @@
error: unconstrained generic constant
--> $DIR/abstract-const-as-cast-2.rs:6:25
--> $DIR/abstract-const-as-cast-2.rs:7:25
|
LL | struct Foo<const N: u8>([u8; N as usize])
| ^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); N as usize]:`
help: try adding a `where` bound
|
LL | Evaluatable<{N as u128}>:, [(); N as usize]:;
| +++++++++++++++++++

error: unconstrained generic constant
--> $DIR/abstract-const-as-cast-2.rs:12:26
--> $DIR/abstract-const-as-cast-2.rs:13:26
|
LL | struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
help: try adding a `where` bound
|
LL | struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:, [(); {N as u128} as usize]:;
| +++++++++++++++++++++++++++++

error: unconstrained generic constant
--> $DIR/abstract-const-as-cast-2.rs:16:25
--> $DIR/abstract-const-as-cast-2.rs:17:25
|
LL | struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
| ^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
help: try adding a `where` bound
|
LL | struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:, [(); (N + 2) as usize]:;
| +++++++++++++++++++++++++

error: aborting due to 3 previous errors

Expand Up @@ -4,7 +4,6 @@ error: unconstrained generic constant
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
note: required for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>` to implement `Trait`
--> $DIR/abstract-const-as-cast-3.rs:8:22
|
Expand All @@ -15,6 +14,10 @@ note: required by a bound in `use_trait_impl::assert_impl`
|
LL | fn assert_impl<T: Trait>() {}
| ^^^^^ required by this bound in `assert_impl`
help: try adding a `where` bound
|
LL | EvaluatableU128<{N as u128}>:, [(); { O as u128 } as usize]: {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0308]: mismatched types
--> $DIR/abstract-const-as-cast-3.rs:17:5
Expand All @@ -36,7 +39,6 @@ error: unconstrained generic constant
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
note: required for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>` to implement `Trait`
--> $DIR/abstract-const-as-cast-3.rs:8:22
|
Expand All @@ -47,6 +49,10 @@ note: required by a bound in `use_trait_impl::assert_impl`
|
LL | fn assert_impl<T: Trait>() {}
| ^^^^^ required by this bound in `assert_impl`
help: try adding a `where` bound
|
LL | EvaluatableU128<{N as u128}>:, [(); { O as u128 } as usize]: {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0308]: mismatched types
--> $DIR/abstract-const-as-cast-3.rs:20:5
Expand Down Expand Up @@ -96,7 +102,6 @@ error: unconstrained generic constant
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
note: required for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>` to implement `Trait`
--> $DIR/abstract-const-as-cast-3.rs:8:22
|
Expand All @@ -107,6 +112,10 @@ note: required by a bound in `use_trait_impl_2::assert_impl`
|
LL | fn assert_impl<T: Trait>() {}
| ^^^^^ required by this bound in `assert_impl`
help: try adding a `where` bound
|
LL | EvaluatableU128<{N as _}>:, [(); { O as u128 } as usize]: {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0308]: mismatched types
--> $DIR/abstract-const-as-cast-3.rs:35:5
Expand All @@ -128,7 +137,6 @@ error: unconstrained generic constant
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
note: required for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>` to implement `Trait`
--> $DIR/abstract-const-as-cast-3.rs:8:22
|
Expand All @@ -139,6 +147,10 @@ note: required by a bound in `use_trait_impl_2::assert_impl`
|
LL | fn assert_impl<T: Trait>() {}
| ^^^^^ required by this bound in `assert_impl`
help: try adding a `where` bound
|
LL | EvaluatableU128<{N as _}>:, [(); { O as u128 } as usize]: {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0308]: mismatched types
--> $DIR/abstract-const-as-cast-3.rs:38:5
Expand Down
Expand Up @@ -4,7 +4,10 @@ error: unconstrained generic constant
LL | bar::<{ N as usize as usize }>();
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { N as usize as usize }]:`
help: try adding a `where` bound
|
LL | fn foo<const N: u8>(a: [(); N as usize]) where [(); { N as usize as usize }]: {
| ++++++++++++++++++++++++++++++++++++

error: aborting due to 1 previous error

Expand Up @@ -4,7 +4,10 @@ error: unconstrained generic constant
LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
| ^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); 0 + N]:`
help: try adding a `where` bound
|
LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]) where [(); 0 + N]:;
| ++++++++++++++++++

error: overly complex generic constant
--> $DIR/array-size-in-generic-struct-param.rs:23:15
Expand Down
Expand Up @@ -4,7 +4,10 @@ error: unconstrained generic constant
LL | bar::<{ T::ASSOC }>();
| ^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { T::ASSOC }]:`
help: try adding a `where` bound
|
LL | fn foo<T: Trait, U: Trait>() where [(); U::ASSOC]:, [(); { T::ASSOC }]: {
| ~~~~~~~~~~~~~~~~~~~~~

error: aborting due to 1 previous error

Expand Up @@ -24,7 +24,10 @@ error: unconstrained generic constant
LL | foo::<_, L>([(); L + 1 + L]);
| ^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:`
help: try adding a `where` bound
|
LL | [(); (L - 1) + 1 + L]:, [(); L + 1 + L]:
| ~~~~~~~~~~~~~~~~~~

error: unconstrained generic constant
--> $DIR/issue_114151.rs:17:17
Expand All @@ -34,11 +37,6 @@ LL | foo::<_, L>([(); L + 1 + L]);
| |
| required by a bound introduced by this call
|
= help: try adding a `where` bound using this expression: `where [(); {
{
N
}
}]:`
note: required by a bound in `foo`
--> $DIR/issue_114151.rs:5:13
|
Expand All @@ -51,6 +49,14 @@ LL | | N
LL | | }
LL | | }],
| |_____^ required by this bound in `foo`
help: try adding a `where` bound
|
LL ~ [(); (L - 1) + 1 + L]:, [(); {
LL + {
LL + N
LL + }
LL + }]:
|

error: unconstrained generic constant `L + 1 + L`
--> $DIR/issue_114151.rs:17:5
Expand Down
Expand Up @@ -13,7 +13,10 @@ error: unconstrained generic constant
LL | Bar::<{ make_generic(N, 1_u8 == 0_u8) }>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { make_generic(N, 1_u8 == 0_u8) }]:`
help: try adding a `where` bound
|
LL | fn foo<const N: usize>() -> Bar<{ make_generic(N, true == false) }> where [(); { make_generic(N, 1_u8 == 0_u8) } as usize]: {
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++

error: aborting due to 2 previous errors

Expand Down
Expand Up @@ -13,7 +13,10 @@ error: unconstrained generic constant
LL | [(); (1_u8 as usize) + N]
| ^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); (1_u8 as usize) + N]:`
help: try adding a `where` bound
|
LL | fn foo<const N: usize>() -> [(); (true as usize) + N] where [(); (1_u8 as usize) + N]: {
| ++++++++++++++++++++++++++++++++

error: aborting due to 2 previous errors

Expand Down
Expand Up @@ -13,7 +13,10 @@ error: unconstrained generic constant
LL | foo::<_, L>([(); L + 1 + L]);
| ^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:`
help: try adding a `where` bound
|
LL | [(); (L - 1) + 1 + L]:, [(); L + 1 + L]:
| ~~~~~~~~~~~~~~~~~~

error: aborting due to 2 previous errors

Expand Down

0 comments on commit 449db0e

Please sign in to comment.