Skip to content

ICE: unexpected type encountered in variance inference in rustc_hir_analysis/src/variance/constraints.rs #125957

Open
@cushionbadak

Description

Code

(hand-reduced & simplified)

#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
#![feature(associated_const_equality)]

pub struct Equal<const T: usize, const R: usize>();

pub enum ParseMode {
    Raw,
}
pub trait Parse {
    const PARSE_MODE: ParseMode;
}
pub trait RenderRaw: Parse<PARSE_MODE = { ParseMode::Raw }> {}

trait GenericVec<T> {
    fn unwrap() -> dyn RenderRaw;
}

fn main() {}
(original, 300+ lines)

//@ check-pass
#![feature(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() {}


#![feature(generic_associated_types)]

trait Fun {
    type F<'a>: Fn() -> u32;
    
    fn callme<'a>(f: Self::F<'a>) -> u32 {
        f()
    }
}

impl <T> Fun for T {
    type F<'a> = Self;
}

fn main() {
    <u8>::callme(0);
}


#![allow(incomplete_features)]
#![feature(adt_const_params, const_ptr_read, generic_const_exprs)]

use std::mem::ManuallyDrop;

const fn concat_strs<const A: &'static str, const B: &'static str>() -> &'static str
where
    [(); A.len()]:,
    [(); B.len()]:,
    [(); A.len() + B.len()]:,
{
    #[repr(C)]
    struct ConcatJoin<const N: usize, const M: usize> {
        left: [u8; N],
        right: [u8; M],
    }

    #[repr(C)]
    union ConcatJoinerItem
    where
        [(); N + M]:,
    {
        whole: ManuallyDrop<[u8; N + M]>,
        split: ManuallyDrop<ConcatJoin<N, M>>,
    }

    const fn concat_arr<const M: usize, const N: usize>(a: [u8; M], b: [u8; N]) -> [u8; M + N]
    where
        [(); M + N]:,
    {
        unsafe {
            let joiner = ConcatJoiner {
                split: ManuallyDrop::new(ConcatJoin { left: a, right: b }),
            };
            let join = joiner.whole;
            ManuallyDrop::into_inner(join)
        }
    }

    struct Inner<const A: &'static str, const B: &'static str>;
    impl<const A: &'static str, const B: &'static str> Inner<A, B>
    where
        [(); A.len()]:,
        [(); B.len()]:,
        [(); A.len() + B.len()]:,
    {
        const ABSTR: &'static str = unsafe {
            std::str::from_utf8_unchecked(&concat_arr(
                A.as_ptr().cast::<[u8; A.len()]>().read(),
                B.as_ptr().cast::<[u8; B.len()]>().read(),
            ))
        };
    }

    Inner::<A, B>::ABSTR
}

const FOO: &str = "foo";
const BAR: &str = "bar";
const FOOBAR: &str = concat_strs::<FOO, BAR>();

pub fn main() {}


//@ aux-build:issue-20727.rs
//@ ignore-cross-compile

// https://github.com/rust-lang/rust/issues/20727
#![crate_name="issue_20727_3"]

extern crate issue_20727;

pub trait Bar {}

// @has issue_20727_3/trait.Deref2.html
pub trait Deref2 {
    // @has - '//pre[@class="rust item-decl"]' 'trait Deref2 {'
    // @has - '//pre[@class="rust item-decl"]' 'type Target: Bar;'
    type Target: Bar;

    // @has - '//pre[@class="rust item-decl"]' 'fn deref(&self) -> Self::Target;'
    fn deref(&self) -> Self::Target;
}

// @has issue_20727_3/reexport/trait.Deref2.html
pub mod reexport {
    // @has - '//pre[@class="rust item-decl"]' 'trait Deref2 {'
    // @has - '//pre[@class="rust item-decl"]' 'type Target: Bar;'
    // @has - '//pre[@class="rust item-decl"]' 'fn deref(&self) -> Self::Target;'
    pub use issue_20727::Deref2;
}


#![feature(associated_const_equality)]
pub enum ParseMode {
    Raw,
}
pub trait Parse {
    const PARSE_MODE: Self::F;
}
pub trait RenderRaw: Parse<PARSE_MODE = { ParseMode::Raw }> {}


// Regression test for #53570. Here, we need to propagate that `T: 'a`
// but in some versions of NLL we were propagating a stronger
// requirement that `T: 'static`. This arose because we actually had
// to propagate both that `T: 'a` but also `T: 'b` where `'b` is the
// higher-ranked lifetime that appears in the type of the closure
// parameter `x` -- since `'b` cannot be expressed in the caller's
// space, that got promoted th `'static`.
//
//@ check-pass

use std::cell::{RefCell, Ref};

trait AnyVec {
}

trait GenericVec<T> {
    fn unwrap<'a, 'b>(vec: &'b dyn AnyVec<'a>) -> &'b [RenderRaw] where T: 'a;
}

struct Scratchpad<'a> {
    buffers: RefCell<Box<dyn AnyVec<'a>>>,
}

impl<'a> Scratchpad<'a> {
    fn get<Deref2>(&self) -> Ref<[T]>
    where T: 'a
    {
        Ref::map(self.buffers.borrow(), |x| T::unwrap(x.as_ref()))
    }
}

fn main() { }

Meta

rustc --version --verbose:

rustc 1.80.0-nightly (7c52d2db6 2024-06-03)
binary: rustc
commit-hash: 7c52d2db6348b038276198e88a835125849f322e
commit-date: 2024-06-03
host: x86_64-apple-darwin
release: 1.80.0-nightly
LLVM version: 18.1.6

Error output

Command: rustc

<output>
Backtrace

error: internal compiler error: compiler/rustc_hir_analysis/src/variance/constraints.rs:331:17: unexpected type encountered in variance inference: FreshTy(0)

thread 'rustc' panicked at compiler/rustc_hir_analysis/src/variance/constraints.rs:331:17:
Box<dyn Any>
stack backtrace:
   0: std::panicking::begin_panic::<rustc_errors::ExplicitBug>
   1: <rustc_errors::diagnostic::BugAbort as rustc_errors::diagnostic::EmissionGuarantee>::emit_producing_guarantee
   2: rustc_middle::util::bug::opt_span_bug_fmt::<rustc_span::span_encoding::Span>::{closure#0}
   3: rustc_middle::ty::context::tls::with_opt::<rustc_middle::util::bug::opt_span_bug_fmt<rustc_span::span_encoding::Span>::{closure#0}, !>::{closure#0}
   4: rustc_middle::ty::context::tls::with_context_opt::<rustc_middle::ty::context::tls::with_opt<rustc_middle::util::bug::opt_span_bug_fmt<rustc_span::span_encoding::Span>::{closure#0}, !>::{closure#0}, !>
   5: rustc_middle::util::bug::bug_fmt
   6: <rustc_hir_analysis::variance::constraints::ConstraintContext>::add_constraints_from_ty
   7: <rustc_hir_analysis::variance::constraints::ConstraintContext>::add_constraints_from_invariant_args
   8: <rustc_hir_analysis::variance::constraints::ConstraintContext>::add_constraints_from_ty
   9: <rustc_hir_analysis::variance::constraints::ConstraintContext>::build_constraints_for_item
  10: rustc_hir_analysis::variance::crate_variances
      [... omitted 1 frame ...]
  11: rustc_hir_analysis::variance::variances_of
      [... omitted 2 frames ...]
  12: rustc_middle::query::plumbing::query_get_at::<rustc_query_system::query::caches::DefIdCache<rustc_middle::query::erase::Erased<[u8; 16]>>>
  13: rustc_hir_analysis::check::wfcheck::check_variances_for_type_defn
  14: rustc_hir_analysis::check::wfcheck::check_well_formed
      [... omitted 1 frame ...]
  15: rustc_middle::query::plumbing::query_ensure_error_guaranteed::<rustc_query_system::query::caches::VecCache<rustc_hir::hir_id::OwnerId, rustc_middle::query::erase::Erased<[u8; 1]>>, ()>
  16: rustc_hir_analysis::check::wfcheck::check_mod_type_wf
      [... omitted 1 frame ...]
  17: rustc_hir_analysis::check_crate
  18: rustc_interface::passes::run_required_analyses
  19: rustc_interface::passes::analysis
      [... omitted 1 frame ...]
  20: <rustc_interface::queries::QueryResult<&rustc_middle::ty::context::GlobalCtxt>>::enter::<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#0}::{closure#1}::{closure#3}>
  21: rustc_interface::interface::run_compiler::<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#0}>::{closure#1}
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: please make sure that you have updated to the latest nightly

note: please attach the file at `/Volumes/T7/workspace/240604_combine_gb/icefiles/rustc-ice-2024-06-04T05_59_01-56677.txt` to your bug report

query stack during panic:
#0 [crate_variances] computing the variances for items in this crate
#1 [variances_of] computing the variances of `Equal`
#2 [check_well_formed] checking that `Equal` is well-formed
#3 [check_mod_type_wf] checking that types are well-formed in top-level module
#4 [analysis] running analysis passes on this crate
end of query stack
error: aborting due to 1 previous error

Note

  • ICE location: rustc_hir_analysis/src/variance/constraints.rs L331
    ty::Placeholder(..) | ty::CoroutineWitness(..) | ty::Bound(..) | ty::Infer(..) => {
    bug!("unexpected type encountered in variance inference: {}", ty);
    }
    • Fixed ICE issue-109071 has identical ICE location
  • If the struct definition pub struct Equal<const T: usize, const R: usize>(); is erased, an ICE will occur at compiler/rustc_infer/src/infer/relate/generalize.rs L456. My guess is that this has already been reported in issue ICE: unexpected infer type #123140.
    let g = match *t.kind() {
    ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
    bug!("unexpected infer type: {t}")
    }

Metadata

Assignees

Labels

C-bugCategory: This is a bug.F-associated_const_equality`#![feature(associated_const_equality)]`F-generic_const_exprs`#![feature(generic_const_exprs)]`I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️S-bug-has-testStatus: This bug is tracked inside the repo by a `known-bug` test.S-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-incomplete-featuresThis issue requires the use of incomplete features.

Type

No type

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions