-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #107940 - BoxyUwU:const_ty_assertion_use_semantic_equal…
…ity, r=compiler-errors use semantic equality for const param type equality assertion Fixes #107898 See added test for what caused this ICE --- The current in assertion in `relate.rs` is rather inadequate when keeping in mind future expansions to const generics: - it will ICE when there are infer vars in a projection in a const param ty - it will spurriously return false when either ty has infer vars because of using `==` instead of `infcx.at(..).eq` - i am also unsure if it would be possible with `adt_const_params` to craft a situation where the const param type is not wf causing `normalize_erasing_regions` to `bug!` when we would have emitted a diagnostic. This impl feels pretty Not Great to me although i am not sure what a better idea would be. - We have to have the logic behind a query because neither `relate.rs` or `combine.rs` have access to trait solving machinery (without evaluating nested obligations this assert will become _far_ less useful under lazy norm, which consts are already doing) - `relate.rs` does not have access to canonicalization machinery which is necessary in order to have types potentially containing infer vars in query arguments. We could possible add a method to `TypeRelation` to do this assertion rather than a query but to avoid implementing the same logic over and over we'd probably end up with the logic in a free function somewhere in `rustc_trait_selection` _anyway_ so I don't think that would be much better. We could also just remove this assertion, it should not actually be necessary for it to be present. It has caught some bugs in the past though so if possible I would like to keep it. r? `@compiler-errors`
- Loading branch information
Showing
7 changed files
with
240 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_1.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// 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() {} |
151 changes: 151 additions & 0 deletions
151
tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// 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() {} |