Skip to content

Commit

Permalink
Provide structured suggestion for unconstrained generic constant
Browse files Browse the repository at this point in the history
```
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 #122395.
  • Loading branch information
estebank committed Mar 21, 2024
1 parent a128516 commit 6b24fdf
Show file tree
Hide file tree
Showing 41 changed files with 351 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3538,12 +3538,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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

Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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

Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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

Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading

0 comments on commit 6b24fdf

Please sign in to comment.