Change:
<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</detailsThis occurred in code different from the above but this is a minimal example that causes this failure. I believe I am disobeying some rules in the manner in which is not bound in the underlying type of the trait. This bug appeared in my own code that worked with a previous nightly build. That code does bind into the underlying type and still fails. If I bind it in this example with the following changes: the error goes away. I will need to create a minimal example that produces an ICE closer to the failure in my own code but I was struggling to do this. This is at least one ICE of interest and perhaps the unbound should itself be prevented. I'm not entirely sure. Worthy of note, the following also compiles fine: which omits all of the stuff.
I've isolated it to the following commit range: ..
I determined it was due to the above linked-from PR.
Prior to this PR, the above code would emit the following warning instead of generating the ICE:
This is caused by the fact that acts sort of like a const item with a const param ty the references other generic parameters: . When we relate the in we constrain infer vars to be the same as eachother but do not end up actually resolving the infer vars before relating so the assertion that const param ty's are sees two different infer vars instead of the resolved ones.

Discussion:
use crate::traits::{Obligation, PredicateObligations}; use rustc_data_structures::sso::SsoHashMap; use rustc_hir::def_id::DefId; <ins> use rustc_middle::infer::canonical::OriginalQueryValues; </ins> use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; <ins> use rustc_middle::traits::query::NoSolution; </ins> use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};

let a = self.shallow_resolve(a); let b = self.shallow_resolve(b); <ins> // 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(), a.ty(), b.ty()), &mut OriginalQueryValues::default(), ); if let Err(NoSolution) = self.tcx.check_tys_might_be_eq(canonical) { self.tcx.sess.delay_span_bug( DUMMY_SP, &format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,), ); } }); </ins> match (a.kind(), b.kind()) { ( ty::ConstKind::Infer(InferConst::Var(a_vid)),

desc { "traits in scope for documentation links for a module" } separate_provide_extern } <ins> /// 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 unequal, but will never return `Err` if /// the types might be equal. query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> { desc { "check whether two const param are definitely not equal to eachother"} } </ins> }

use crate::ty::{GenericArg, GenericArgKind, SubstsRef}; use rustc_hir as ast; use rustc_hir::def_id::DefId; <del> use rustc_span::DUMMY_SP; </del> use rustc_target::spec::abi; use std::iter;

debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); <del> let a_ty; let b_ty; if relation.tcx().features().adt_const_params { a_ty = tcx.normalize_erasing_regions(relation.param_env(), a.ty()); b_ty = tcx.normalize_erasing_regions(relation.param_env(), b.ty()); } else { a_ty = tcx.erase_regions(a.ty()); b_ty = tcx.erase_regions(b.ty()); } if a_ty != b_ty { relation.tcx().sess.delay_span_bug( DUMMY_SP, &format!( "cannot relate constants ({:?}, {:?}) of different types: {} != {}", a, b, a_ty, b_ty ), ); } </del> // HACK(const_generics): We still need to eagerly evaluate consts when // relating them because during `normalize_param_env_or_error`, // we may relate an evaluated constant in a obligation against

//! Miscellaneous type-system utilities that are too small to deserve their own modules. <del> use crate::traits::{self, ObligationCause}; </del> <ins> use crate::traits::{self, ObligationCause, ObligationCtxt}; </ins> use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; <ins> use rustc_infer::infer::canonical::Canonical; </ins> use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; <ins> use rustc_infer::traits::query::NoSolution; </ins> use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; <del> use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; </del> <ins> use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitable}; use rustc_span::DUMMY_SP; </ins> use super::outlives_bounds::InferCtxtExt;

Ok(()) } <ins> pub fn check_tys_might_be_eq<'tcx>( tcx: TyCtxt<'tcx>, canonical: Canonical<'tcx, (ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>, ) -> Result<(), NoSolution> { let (infcx, (param_env, ty_a, ty_b), _) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical); 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(()) } } </ins>

specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, subst_and_check_impossible_predicates, <ins> check_tys_might_be_eq: misc::check_tys_might_be_eq, </ins> is_impossible_method, ..*providers };

<ins> // check-pass #![feature(generic_const_exprs)] #![allow(incomplete_features)] // issue #107899 // We end up relating `Const(ty: size_of<?0>, kind: Value(Branch([])))` with // `Const(ty: size_of<T>, kind: Value(Branch([])))` which if you were to `==` // the `ty` fields would return `false` and ICE. This test checks that we use // actual semantic equality that takes into account aliases and infer vars. use std::mem::size_of; trait X<T> { fn f(self); fn g(self); } struct Y; impl<T> X<T> for Y where [(); size_of::<T>()]: Sized, { fn f(self) { self.g(); } fn g(self) {} } fn main() {} </ins>

<ins> // check-pass #![feature(inline_const, generic_const_exprs)] #![allow(incomplete_features)] use std::marker::PhantomData; pub struct Equal<const T: usize, const R: usize>(); pub trait True {} impl<const T: usize> True for Equal<T, T> {} // replacement for generativity pub struct Id<'id>(PhantomData<fn(&'id ()) -> &'id ()>); pub struct Guard<'id>(Id<'id>); fn make_guard<'id>(i: &'id Id<'id>) -> Guard<'id> { Guard(Id(PhantomData)) } impl<'id> Into<Id<'id>> for Guard<'id> { fn into(self) -> Id<'id> { self.0 } } pub struct Arena<'life> { bytes: *mut [u8], //bitmap: RefCell<RoaringBitmap>, _token: PhantomData<Id<'life>>, } #[repr(transparent)] pub struct Item<'life, T> { data: T, _phantom: PhantomData<Id<'life>>, } #[repr(transparent)] pub struct Token<'life, 'borrow, 'compact, 'reborrow, T> where 'life: 'reborrow, T: Tokenize<'life, 'borrow, 'compact, 'reborrow>, { //ptr: *mut <T as Tokenize>::Tokenized, ptr: core::ptr::NonNull<T::Tokenized>, _phantom: PhantomData<Id<'life>>, _compact: PhantomData<&'borrow Guard<'compact>>, _result: PhantomData<&'reborrow T::Untokenized>, } impl<'life> Arena<'life> { pub fn tokenize<'before, 'compact, 'borrow, 'reborrow, T, U>( &self, guard: &'borrow Guard<'compact>, item: Item<'life, &'before mut T>, ) -> Token<'life, 'borrow, 'compact, 'reborrow, U> where T: Tokenize<'life, 'borrow, 'compact, 'reborrow, Untokenized = U>, T::Untokenized: Tokenize<'life, 'borrow, 'compact, 'reborrow>, Equal<{ core::mem::size_of::<T>() }, { core::mem::size_of::<U>() }>: True, 'compact: 'borrow, 'life: 'reborrow, 'life: 'compact, 'life: 'borrow, // 'borrow: 'before ?? { let dst = item.data as *mut T as *mut T::Tokenized; Token { ptr: core::ptr::NonNull::new(dst as *mut _).unwrap(), _phantom: PhantomData, _compact: PhantomData, _result: PhantomData, } } } pub trait Tokenize<'life, 'borrow, 'compact, 'reborrow> where 'compact: 'borrow, 'life: 'reborrow, 'life: 'borrow, 'life: 'compact, { type Tokenized; type Untokenized; const TO: fn(&Arena<'life>, &'borrow Guard<'compact>, Self) -> Self::Tokenized; const FROM: fn(&'reborrow Arena<'life>, Self::Tokenized) -> Self::Untokenized; } macro_rules! tokenize { ($to:expr, $from:expr) => { const TO: fn(&Arena<'life>, &'borrow Guard<'compact>, Self) -> Self::Tokenized = $to; const FROM: fn(&'reborrow Arena<'life>, Self::Tokenized) -> Self::Untokenized = $from; }; } struct Foo<'life, 'borrow>(Option<Item<'life, &'borrow mut Bar>>); struct TokenFoo<'life, 'borrow, 'compact, 'reborrow>( Option<Token<'life, 'borrow, 'compact, 'reborrow, Bar>>, ); struct Bar(u8); impl<'life, 'before, 'borrow, 'compact, 'reborrow> Tokenize<'life, 'borrow, 'compact, 'reborrow> for Foo<'life, 'before> where 'compact: 'borrow, 'life: 'reborrow, 'life: 'borrow, 'life: 'compact, { type Tokenized = TokenFoo<'life, 'borrow, 'compact, 'reborrow>; type Untokenized = Foo<'life, 'reborrow>; tokenize!(foo_to, foo_from); } impl<'life, 'borrow, 'compact, 'reborrow> Tokenize<'life, 'borrow, 'compact, 'reborrow> for Bar where 'compact: 'borrow, 'life: 'reborrow, 'life: 'borrow, 'life: 'compact, { type Tokenized = Bar; type Untokenized = Bar; tokenize!(bar_to, bar_from); } fn bar_to<'life, 'borrow, 'compact>( arena: &Arena<'life>, guard: &'borrow Guard<'compact>, s: Bar, ) -> Bar { s } fn bar_from<'life, 'reborrow>(arena: &'reborrow Arena<'life>, s: Bar) -> Bar { s } fn foo_to<'life, 'borrow, 'compact, 'reborrow, 'before>( arena: &'before Arena<'life>, guard: &'borrow Guard<'compact>, s: Foo<'life, 'before>, ) -> TokenFoo<'life, 'borrow, 'compact, 'reborrow> { let Foo(bar) = s; TokenFoo(bar.map(|bar| arena.tokenize(guard, bar))) } fn foo_from<'life, 'borrow, 'compact, 'reborrow>( arena: &'reborrow Arena<'life>, s: TokenFoo<'life, 'borrow, 'compact, 'reborrow>, ) -> Foo<'life, 'reborrow> { Foo(s.0.map(|bar| panic!())) } fn main() {} </ins>