Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fail relating constants of different types #125451

Merged
merged 2 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading