Rollup merge of #125451 - oli-obk:const_type_mismatch, r=compiler-errors
Fail relating constants of different types fixes #121585 fixes #121858 fixes #124151 I gave this several attempts before, but we lost too many important diagnostics until I managed to make compilation never bail out early. We have reached this point, so now we can finally fix all those ICEs by bubbling up an error instead of continueing when we encounter a bug.
This commit is contained in:
commit
7ea507e041
@ -22,11 +22,11 @@
|
||||
use super::lub::Lub;
|
||||
use super::type_relating::TypeRelating;
|
||||
use super::StructurallyRelateAliases;
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::infer::canonical::OriginalQueryValues;
|
||||
use rustc_middle::infer::unify_key::EffectVarValue;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
|
||||
@ -159,36 +159,11 @@ pub fn super_combine_consts<R>(
|
||||
let a = self.shallow_resolve_const(a);
|
||||
let b = self.shallow_resolve_const(b);
|
||||
|
||||
// We should never have to relate the `ty` field on `Const` as it is checked elsewhere that consts have the
|
||||
// correct type for the generic param they are an argument for. However there have been a number of cases
|
||||
// historically where asserting that the types are equal has found bugs in the compiler so this is valuable
|
||||
// to check even if it is a bit nasty impl wise :(
|
||||
//
|
||||
// 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.
|
||||
self.probe(|_| {
|
||||
if a.ty() == b.ty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
|
||||
// two const param's types are able to be equal has to go through a canonical query with the actual logic
|
||||
// in `rustc_trait_selection`.
|
||||
let canonical = self.canonicalize_query(
|
||||
relation.param_env().and((a.ty(), b.ty())),
|
||||
&mut OriginalQueryValues::default(),
|
||||
);
|
||||
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.
|
||||
});
|
||||
});
|
||||
// It is always an error if the types of two constants that are related are not equal.
|
||||
let InferOk { value: (), obligations } = self
|
||||
.at(&ObligationCause::dummy_with_span(relation.span()), relation.param_env())
|
||||
.eq(DefineOpaqueTypes::No, a.ty(), b.ty())?;
|
||||
relation.register_obligations(obligations);
|
||||
|
||||
match (a.kind(), b.kind()) {
|
||||
(
|
||||
|
@ -2218,15 +2218,6 @@
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// Used in `super_combine_consts` to ICE if the type of the two consts are definitely not going to end up being
|
||||
/// equal to eachother. This might return `Ok` even if the types are not equal, but will never return `Err` if
|
||||
/// the types might be equal.
|
||||
query check_tys_might_be_eq(
|
||||
arg: Canonical<'tcx, ty::ParamEnvAnd<'tcx, (Ty<'tcx>, Ty<'tcx>)>>
|
||||
) -> Result<(), NoSolution> {
|
||||
desc { "check whether two const param are definitely not equal to eachother"}
|
||||
}
|
||||
|
||||
/// Get all item paths that were stripped by a `#[cfg]` in a particular crate.
|
||||
/// Should not be called for the local crate before the resolver outputs are created, as it
|
||||
/// is only fed there.
|
||||
|
@ -1,17 +1,14 @@
|
||||
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
|
||||
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::traits::{self, ObligationCause, ObligationCtxt};
|
||||
use crate::traits::{self, ObligationCause};
|
||||
|
||||
use hir::LangItem;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
|
||||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use super::outlives_bounds::InferCtxtExt;
|
||||
|
||||
@ -207,19 +204,3 @@ pub fn all_fields_implement_trait<'tcx>(
|
||||
|
||||
if infringing.is_empty() { Ok(()) } else { Err(infringing) }
|
||||
}
|
||||
|
||||
pub fn check_tys_might_be_eq<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonical: Canonical<'tcx, ty::ParamEnvAnd<'tcx, (Ty<'tcx>, Ty<'tcx>)>>,
|
||||
) -> Result<(), NoSolution> {
|
||||
let (infcx, key, _) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical);
|
||||
let (param_env, (ty_a, ty_b)) = key.into_parts();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let result = ocx.eq(&ObligationCause::dummy(), param_env, ty_a, ty_b);
|
||||
// use `select_where_possible` instead of `select_all_or_error` so that
|
||||
// we don't get errors from obligations being ambiguous.
|
||||
let errors = ocx.select_where_possible();
|
||||
|
||||
if errors.len() > 0 || result.is_err() { Err(NoSolution) } else { Ok(()) }
|
||||
}
|
||||
|
@ -551,7 +551,6 @@ pub fn provide(providers: &mut Providers) {
|
||||
specialization_graph_of: specialize::specialization_graph_provider,
|
||||
specializes: specialize::specializes,
|
||||
instantiate_and_check_impossible_predicates,
|
||||
check_tys_might_be_eq: misc::check_tys_might_be_eq,
|
||||
is_impossible_associated_item,
|
||||
..*providers
|
||||
};
|
||||
|
@ -1,6 +0,0 @@
|
||||
//@ known-bug: #119381
|
||||
|
||||
#![feature(with_negative_coherence)]
|
||||
trait Trait {}
|
||||
impl<const N: u8> Trait for [(); N] {}
|
||||
impl<const N: i8> Trait for [(); N] {}
|
@ -1,13 +0,0 @@
|
||||
//@ known-bug: #121585
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
trait Trait {}
|
||||
|
||||
struct HasCastInTraitImpl<const N: usize, const M: u128>;
|
||||
impl<const O: f64> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
|
||||
|
||||
pub fn use_trait_impl() {
|
||||
fn assert_impl<T: Trait>() {}
|
||||
|
||||
assert_impl::<HasCastInTraitImpl<13, 13>>();
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
//@ known-bug: #121585
|
||||
//@ check-pass
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait {}
|
||||
pub struct EvaluatableU128<const N: u128>;
|
||||
|
||||
struct HasCastInTraitImpl<const N: usize, const M: u128>;
|
||||
impl<const O: f64> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
|
||||
|
||||
pub fn use_trait_impl<const N: usize>() where EvaluatableU128<{N as u128}>:, {
|
||||
fn assert_impl<T: Trait>() {}
|
||||
|
||||
assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
|
||||
assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
|
||||
assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
|
||||
assert_impl::<HasCastInTraitImpl<13, 13>>();
|
||||
}
|
||||
pub fn use_trait_impl_2<const N: usize>() where EvaluatableU128<{N as _}>:, {
|
||||
fn assert_impl<T: Trait>() {}
|
||||
|
||||
assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
|
||||
assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
|
||||
assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>()const NUM: u8 = xyz();
|
||||
assert_impl::<HasCastInTraitImpl<13, 13>>();
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
@ -1,20 +0,0 @@
|
||||
//@ known-bug: #121858
|
||||
#![allow(named_arguments_used_positionally)]
|
||||
#![feature(generic_const_exprs)]
|
||||
struct Inner<const N: usize, const M: usize>;
|
||||
impl<const N: usize, const M: usize> Inner<N, M> where [(); N + M]: {
|
||||
fn i() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
struct Outer<const A: i64, const B: usize>(Inner<A, { B * 2 }>) where [(); A + (B * 2)]:;
|
||||
impl<const A: usize, const B: usize> Outer<A, B> where [(); A + (B * 2)]: {
|
||||
fn o() -> Union {
|
||||
Self(Inner::i())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Outer::<1, 1>::o();
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
//@ known-bug: #124151
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
pub struct Dimension;
|
||||
|
||||
pub struct Quantity<S, const D: Dimension>(S);
|
||||
|
||||
impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
|
||||
|
||||
pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
|
||||
x + y
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
//! This test used to ICE (#119381), because relating the `u8` and `i8` generic
|
||||
//! const with the array length of the `Self` type was succeeding under the
|
||||
//! assumption that an error had already been reported.
|
||||
|
||||
#![feature(with_negative_coherence)]
|
||||
trait Trait {}
|
||||
impl<const N: u8> Trait for [(); N] {}
|
||||
//~^ ERROR: mismatched types
|
||||
impl<const N: i8> Trait for [(); N] {}
|
||||
//~^ ERROR: mismatched types
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,15 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/generic_const_type_mismatch.rs:7:34
|
||||
|
|
||||
LL | impl<const N: u8> Trait for [(); N] {}
|
||||
| ^ expected `usize`, found `u8`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/generic_const_type_mismatch.rs:9:34
|
||||
|
|
||||
LL | impl<const N: i8> Trait for [(); N] {}
|
||||
| ^ expected `usize`, found `i8`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -11,4 +11,4 @@ trait Q {
|
||||
}
|
||||
|
||||
pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
|
||||
//~^ ERROR: the constant `13` is not of type `u64`
|
||||
//~^ ERROR: `[u8; 13]: Q` is not satisfied
|
||||
|
@ -1,16 +1,10 @@
|
||||
error: the constant `13` is not of type `u64`
|
||||
error[E0277]: the trait bound `[u8; 13]: Q` is not satisfied
|
||||
--> $DIR/bad-subst-const-kind.rs:13:24
|
||||
|
|
||||
LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
|
||||
| ^^^^^^^^ expected `u64`, found `usize`
|
||||
| ^^^^^^^^ the trait `Q` is not implemented for `[u8; 13]`
|
||||
|
|
||||
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
|
||||
= help: the trait `Q` is implemented for `[u8; N]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/bad-subst-const-kind.rs:8:31
|
||||
@ -20,4 +14,5 @@ LL | impl<const N: u64> Q for [u8; N] {
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -10,7 +10,7 @@ trait Q {
|
||||
//~| ERROR mismatched types
|
||||
|
||||
pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
|
||||
//~^ ERROR the constant `13` is not of type `u64`
|
||||
//~^ ERROR `[u8; 13]: Q` is not satisfied
|
||||
//~| ERROR mismatched types
|
||||
|
||||
pub fn main() {}
|
||||
|
@ -7,19 +7,13 @@ LL | const ASSOC: usize;
|
||||
LL | impl<const N: u64> Q for [u8; N] {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation
|
||||
|
||||
error: the constant `13` is not of type `u64`
|
||||
error[E0277]: the trait bound `[u8; 13]: Q` is not satisfied
|
||||
--> $DIR/type_mismatch.rs:12:26
|
||||
|
|
||||
LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
|
||||
| ^^^^^^^^ expected `u64`, found `usize`
|
||||
| ^^^^^^^^ the trait `Q` is not implemented for `[u8; 13]`
|
||||
|
|
||||
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
|
||||
= help: the trait `Q` is implemented for `[u8; N]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type_mismatch.rs:12:20
|
||||
@ -37,5 +31,5 @@ LL | impl<const N: u64> Q for [u8; N] {}
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0046, E0308.
|
||||
Some errors have detailed explanations: E0046, E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0046`.
|
||||
|
@ -1,4 +1,10 @@
|
||||
//@ check-pass
|
||||
//@ failure-status: 101
|
||||
//@ known-bug: unknown
|
||||
//@ normalize-stderr-test "note: .*\n\n" -> ""
|
||||
//@ normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
|
||||
//@ normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
|
||||
//@ normalize-stderr-test "delayed at .*" -> ""
|
||||
//@ rustc-env:RUST_BACKTRACE=0
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(adt_const_params, generic_const_exprs)]
|
||||
|
8
tests/ui/const-generics/issues/issue-105821.stderr
Normal file
8
tests/ui/const-generics/issues/issue-105821.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: internal compiler error: compiler/rustc_borrowck/src/universal_regions.rs:LL:CC: cannot convert `'{erased}` to a region vid
|
||||
|
||||
query stack during panic:
|
||||
#0 [mir_borrowck] borrow-checking `<impl at $DIR/issue-105821.rs:21:1: 23:24>::R`
|
||||
#1 [analysis] running analysis passes on this crate
|
||||
end of query stack
|
||||
error: aborting due to 1 previous error
|
||||
|
@ -1,14 +1,17 @@
|
||||
//@ known-bug: #121858
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Outer<const A: i64, const B: usize>();
|
||||
impl<const A: usize, const B: usize> Outer<A, B>
|
||||
//~^ ERROR: `A` is not of type `i64`
|
||||
//~| ERROR: mismatched types
|
||||
where
|
||||
[(); A + (B * 2)]:,
|
||||
{
|
||||
fn o() -> Union {}
|
||||
fn o() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Outer::<1, 1>::o();
|
||||
//~^ ERROR: no function or associated item named `o` found
|
||||
}
|
34
tests/ui/consts/eval_type_mismatch.stderr
Normal file
34
tests/ui/consts/eval_type_mismatch.stderr
Normal file
@ -0,0 +1,34 @@
|
||||
error: the constant `A` is not of type `i64`
|
||||
--> $DIR/eval_type_mismatch.rs:5:38
|
||||
|
|
||||
LL | impl<const A: usize, const B: usize> Outer<A, B>
|
||||
| ^^^^^^^^^^^ expected `i64`, found `usize`
|
||||
|
|
||||
note: required by a bound in `Outer`
|
||||
--> $DIR/eval_type_mismatch.rs:4:14
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: usize>();
|
||||
| ^^^^^^^^^^^^ required by this bound in `Outer`
|
||||
|
||||
error[E0599]: no function or associated item named `o` found for struct `Outer<1, 1>` in the current scope
|
||||
--> $DIR/eval_type_mismatch.rs:15:20
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: usize>();
|
||||
| ------------------------------------------ function or associated item `o` not found for this struct
|
||||
...
|
||||
LL | Outer::<1, 1>::o();
|
||||
| ^ function or associated item not found in `Outer<1, 1>`
|
||||
|
|
||||
= note: the function or associated item was found for
|
||||
- `Outer<A, B>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/eval_type_mismatch.rs:5:44
|
||||
|
|
||||
LL | impl<const A: usize, const B: usize> Outer<A, B>
|
||||
| ^ expected `i64`, found `usize`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0599.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
@ -7,7 +7,8 @@
|
||||
|
||||
impl<const N: i32> Copy for S<N> {}
|
||||
//~^ ERROR: mismatched types
|
||||
//~| ERROR: the trait bound `S<N>: Clone` is not satisfied
|
||||
//~| 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() {}
|
||||
|
@ -1,11 +1,29 @@
|
||||
error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:10:1
|
||||
error[E0277]: the trait bound `S<N>: Clone` is not satisfied
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
|
||||
|
|
||||
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<_>`
|
||||
| ^^^^ the trait `Clone` is not implemented for `S<N>`
|
||||
|
|
||||
= help: the trait `Clone` is implemented for `S<L>`
|
||||
note: required by a bound in `Copy`
|
||||
--> $SRC_DIR/core/src/marker.rs:LL:COL
|
||||
help: consider annotating `S<N>` with `#[derive(Clone)]`
|
||||
|
|
||||
LL + #[derive(Clone)]
|
||||
LL | struct S<const L: usize>;
|
||||
|
|
||||
|
||||
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
|
||||
|
|
||||
LL | struct S<const L: usize>;
|
||||
| ^^^^^^^^^^^^^^ required by this bound in `S`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:8:31
|
||||
@ -13,7 +31,7 @@ error[E0308]: mismatched types
|
||||
LL | impl<const N: i32> Copy for S<N> {}
|
||||
| ^ expected `usize`, found `i32`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0119, E0308.
|
||||
For more information about an error, try `rustc --explain E0119`.
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
Loading…
Reference in New Issue
Block a user