Skip to content

Commit

Permalink
Rollup merge of rust-lang#125451 - oli-obk:const_type_mismatch, r=com…
Browse files Browse the repository at this point in the history
…piler-errors

Fail relating constants of different types

fixes rust-lang#121585
fixes rust-lang#121858
fixes rust-lang#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.
  • Loading branch information
matthiaskrgr authored May 25, 2024
2 parents f28d368 + d5eb7a7 commit 7ea507e
Show file tree
Hide file tree
Showing 21 changed files with 129 additions and 180 deletions.
39 changes: 7 additions & 32 deletions compiler/rustc_infer/src/infer/relate/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ use super::glb::Glb;
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};
Expand Down Expand Up @@ -159,36 +159,11 @@ impl<'tcx> InferCtxt<'tcx> {
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()) {
(
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2218,15 +2218,6 @@ rustc_queries! {
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.
Expand Down
21 changes: 1 addition & 20 deletions compiler/rustc_trait_selection/src/traits/misc.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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(()) }
}
1 change: 0 additions & 1 deletion compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down
6 changes: 0 additions & 6 deletions tests/crashes/119381.rs

This file was deleted.

13 changes: 0 additions & 13 deletions tests/crashes/121585-1.rs

This file was deleted.

30 changes: 0 additions & 30 deletions tests/crashes/121585-2.rs

This file was deleted.

20 changes: 0 additions & 20 deletions tests/crashes/121858-2.rs

This file was deleted.

14 changes: 0 additions & 14 deletions tests/crashes/124151.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 1 addition & 1 deletion tests/ui/const-generics/bad-subst-const-kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +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`
//~^ ERROR: `[u8; 13]: Q` is not satisfied
15 changes: 5 additions & 10 deletions tests/ui/const-generics/bad-subst-const-kind.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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`.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ impl<const N: u64> Q for [u8; N] {}
//~| 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() {}
14 changes: 4 additions & 10 deletions tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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`.
8 changes: 7 additions & 1 deletion tests/ui/const-generics/issues/issue-105821.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/const-generics/issues/issue-105821.stderr
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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 changes: 34 additions & 0 deletions tests/ui/consts/eval_type_mismatch.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ struct S<const L: usize>;

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() {}
Loading

0 comments on commit 7ea507e

Please sign in to comment.