Skip to content

Commit

Permalink
Make generic const type mismatches not hide trait impls from the trai…
Browse files Browse the repository at this point in the history
…t solver
  • Loading branch information
oli-obk committed Jan 22, 2024
1 parent 366d112 commit 9454b51
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 31 deletions.
34 changes: 10 additions & 24 deletions compiler/rustc_infer/src/infer/relate/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ impl<'tcx> InferCtxt<'tcx> {
//
// This probe is probably not strictly necessary but it seems better to be safe and not accidentally find
// ourselves with a check to find bugs being required for code to compile because it made inference progress.
let compatible_types = self.probe(|_| {
self.probe(|_| {
if a.ty() == b.ty() {
return Ok(());
return;
}

// We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
Expand All @@ -177,32 +177,18 @@ impl<'tcx> InferCtxt<'tcx> {
relation.param_env().and((a.ty(), b.ty())),
&mut OriginalQueryValues::default(),
);
self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
self.tcx.check_tys_might_be_eq(canonical).unwrap_or_else(|_| {
// The error will only be reported later. If we emit an ErrorGuaranteed
// here, then we will never get to the code that actually emits the error.
self.tcx.dcx().delayed_bug(format!(
"cannot relate consts of different types (a={a:?}, b={b:?})",
))
})
));
// We treat these constants as if they were of the same type, so that any
// such constants being used in impls make these impls match barring other mismatches.
// This helps with diagnostics down the road.
});
});

// If the consts have differing types, just bail with a const error with
// the expected const's type. Specifically, we don't want const infer vars
// to do any type shapeshifting before and after resolution.
if let Err(guar) = compatible_types {
// HACK: equating both sides with `[const error]` eagerly prevents us
// from leaving unconstrained inference vars during things like impl
// matching in the solver.
let a_error = ty::Const::new_error(self.tcx, guar, a.ty());
if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
return self.unify_const_variable(vid, a_error, relation.param_env());
}
let b_error = ty::Const::new_error(self.tcx, guar, b.ty());
if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
return self.unify_const_variable(vid, b_error, relation.param_env());
}

return Ok(if relation.a_is_expected() { a_error } else { b_error });
}

match (a.kind(), b.kind()) {
(
ty::ConstKind::Infer(InferConst::Var(a_vid)),
Expand Down
1 change: 1 addition & 0 deletions tests/ui/const-generics/bad-subst-const-kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ impl<const N: u64> Q for [u8; N] {
}

pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
//~^ ERROR: the constant `13` is not of type `u64`
16 changes: 15 additions & 1 deletion tests/ui/const-generics/bad-subst-const-kind.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
error: the constant `13` is not of type `u64`
--> $DIR/bad-subst-const-kind.rs:13:24
|
LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
| ^^^^^^^^ expected `u64`, found `usize`
|
note: required for `[u8; 13]` to implement `Q`
--> $DIR/bad-subst-const-kind.rs:8:20
|
LL | impl<const N: u64> Q for [u8; N] {
| ------------ ^ ^^^^^^^
| |
| unsatisfied trait bound introduced here

error[E0308]: mismatched types
--> $DIR/bad-subst-const-kind.rs:8:31
|
LL | impl<const N: u64> Q for [u8; N] {
| ^ expected `usize`, found `u64`

error: aborting due to 1 previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0308`.
3 changes: 3 additions & 0 deletions tests/ui/const-generics/generic_const_exprs/type_mismatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ trait Q {

impl<const N: u64> Q for [u8; N] {}
//~^ ERROR not all trait items implemented
//~| ERROR mismatched types

pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
//~^ ERROR the constant `13` is not of type `u64`
//~| ERROR mismatched types

pub fn main() {}
33 changes: 31 additions & 2 deletions tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,35 @@ LL | const ASSOC: usize;
LL | impl<const N: u64> Q for [u8; N] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation

error: aborting due to 1 previous error
error: the constant `13` is not of type `u64`
--> $DIR/type_mismatch.rs:12:26
|
LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
| ^^^^^^^^ expected `u64`, found `usize`
|
note: required for `[u8; 13]` to implement `Q`
--> $DIR/type_mismatch.rs:8:20
|
LL | impl<const N: u64> Q for [u8; N] {}
| ------------ ^ ^^^^^^^
| |
| unsatisfied trait bound introduced here

error[E0308]: mismatched types
--> $DIR/type_mismatch.rs:12:20
|
LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
| ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `[u8; <[u8; 13] as Q>::ASSOC]`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression

error[E0308]: mismatched types
--> $DIR/type_mismatch.rs:8:31
|
LL | impl<const N: u64> Q for [u8; N] {}
| ^ expected `usize`, found `u64`

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0046`.
Some errors have detailed explanations: E0046, E0308.
For more information about an error, try `rustc --explain E0046`.
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ struct S<const L: usize>;
impl<const N: i32> Copy for S<N> {}
//~^ ERROR the constant `N` is not of type `usize`
impl<const M: usize> Copy for S<M> {}
//~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>`

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
--> $DIR/bad-const-wf-doesnt-specialize.rs:10:1
|
LL | impl<const N: i32> Copy for S<N> {}
| -------------------------------- first implementation here
LL |
LL | impl<const M: usize> Copy for S<M> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`

error: the constant `N` is not of type `usize`
--> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
|
LL | impl<const N: i32> Copy for S<N> {}
| ^^^^ expected `usize`, found `i32`
|
note: required by a bound in `S`
--> $DIR/bad-const-wf-doesnt-specialize.rs:6:10
note: required for `S<N>` to implement `Clone`
--> $DIR/bad-const-wf-doesnt-specialize.rs:5:10
|
LL | #[derive(Clone)]
| ^^^^^
LL | struct S<const L: usize>;
| ^^^^^^^^^^^^^^ required by this bound in `S`
| ----- unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `Copy`
--> $SRC_DIR/core/src/marker.rs:LL:COL
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 1 previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0119`.

0 comments on commit 9454b51

Please sign in to comment.