gccrs
gccrs copied to clipboard
Weird root segment type resolution issue depending on order of items?
not sure I can make a lot of sense out of this one. basically, moving around the usage of our Weird type causes a failure in the type resolver. I'm having a hard time reducing the testcase further so any help is appreciated.
#![feature(intrinsics)]
#![feature(lang_items)]
#[lang = "sized"]
trait Sized {}
extern "rust-intrinsic" {
fn transmute<T, U>(_: T) -> U;
fn offset<T>(src: *const T, offset: isize) -> *const T;
}
pub mod core {
pub mod marker {
#[lang = "phantom_data"]
pub struct PhantomData<T>;
}
pub mod slice {
use core::marker::PhantomData;
use core::option::Option;
impl<T> core::iter::IntoIterator for &[T] {
type Item = &T;
type IntoIter = Weird<T>;
fn into_iter(self) -> Weird<T> {
self.iter()
}
}
pub struct Weird<T> {
ptr: *const T, // should be NonNull<T> but here it does not matter
end: *const T,
_marker: PhantomData<&T>,
}
impl<T> Weird<T> {
pub(super) fn new(slice: &[T]) -> Self {
let ptr = slice.as_ptr();
// SAFETY: Similar to `IterMut::new`.
unsafe {
// should be: ptr.add(slice.len())
let end = transmute::<*const T, usize>(ptr) + slice.len(); // TODO(Arthur): Missing `* size_of::<T>()`?
let end = transmute::<usize, *const T>(end);
Self {
ptr,
end,
_marker: PhantomData,
}
}
}
fn is_empty(&self) -> bool {
self.ptr == self.end
}
fn next_unchecked(&mut self) -> *const T {
let old = self.ptr;
self.ptr = unsafe { offset(self.ptr, 1) };
old
}
}
trait Foo {}
impl<T> Foo for Weird<T> {}
// impl<T> core::iter::Iterator for Iter<T> {
// type Item = &T;
// fn next(&mut self) -> Option<&T> {
// if self.is_empty() {
// Option::None
// } else {
// Option::Some(&*self.next_unchecked())
// }
// }
// }
union Repr<T> {
pub(crate) rust: *const [T],
rust_mut: *mut [T],
pub(crate) raw: FatPtr<T>,
}
struct FatPtr<T> {
data: *const T,
pub(crate) len: usize,
}
impl<T> [T] {
pub fn iter(&self) -> Weird<T> {
Weird::new(self)
}
pub fn as_ptr(&self) -> *const T {
self as *const [T] as *const T
}
pub fn len(&self) -> usize {
unsafe { Repr { rust: self }.raw.len }
}
}
}
pub mod iter {
use option::Option;
pub trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;
fn into_iter(self) -> Self::IntoIter;
}
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
}
pub mod option {
pub enum Option<T> {
Some(T),
None,
}
}
}
fn main() {}
causes the following errors:
root-seg.rs:69:25: error: failed to resolve root segment: Weird<T>
69 | impl<T> Foo for Weird<T> {}
| ^~~~~
root-seg.rs:69:17: error: failed to resolve type arguments
69 | impl<T> Foo for Weird<T> {}
| ^~~
but moving the definition of Weird above the implementation of IntoIterator for &[T] results in a successful compilation:
#![feature(intrinsics)]
#![feature(lang_items)]
#[lang = "sized"]
trait Sized {}
extern "rust-intrinsic" {
fn transmute<T, U>(_: T) -> U;
fn offset<T>(src: *const T, offset: isize) -> *const T;
}
pub mod core {
pub mod marker {
#[lang = "phantom_data"]
pub struct PhantomData<T>;
}
pub mod slice {
use core::marker::PhantomData;
use core::option::Option;
pub struct Weird<T> {
ptr: *const T, // should be NonNull<T> but here it does not matter
end: *const T,
_marker: PhantomData<&T>,
}
impl<T> core::iter::IntoIterator for &[T] {
type Item = &T;
type IntoIter = Weird<T>;
fn into_iter(self) -> Weird<T> {
self.iter()
}
}
impl<T> Weird<T> {
pub(super) fn new(slice: &[T]) -> Self {
let ptr = slice.as_ptr();
// SAFETY: Similar to `IterMut::new`.
unsafe {
// should be: ptr.add(slice.len())
let end = transmute::<*const T, usize>(ptr) + slice.len(); // TODO(Arthur): Missing `* size_of::<T>()`?
let end = transmute::<usize, *const T>(end);
Self {
ptr,
end,
_marker: PhantomData,
}
}
}
fn is_empty(&self) -> bool {
self.ptr == self.end
}
fn next_unchecked(&mut self) -> *const T {
let old = self.ptr;
self.ptr = unsafe { offset(self.ptr, 1) };
old
}
}
trait Foo {}
impl<T> Foo for Weird<T> {}
// impl<T> core::iter::Iterator for Iter<T> {
// type Item = &T;
// fn next(&mut self) -> Option<&T> {
// if self.is_empty() {
// Option::None
// } else {
// Option::Some(&*self.next_unchecked())
// }
// }
// }
union Repr<T> {
pub(crate) rust: *const [T],
rust_mut: *mut [T],
pub(crate) raw: FatPtr<T>,
}
struct FatPtr<T> {
data: *const T,
pub(crate) len: usize,
}
impl<T> [T] {
pub fn iter(&self) -> Weird<T> {
Weird::new(self)
}
pub fn as_ptr(&self) -> *const T {
self as *const [T] as *const T
}
pub fn len(&self) -> usize {
unsafe { Repr { rust: self }.raw.len }
}
}
}
pub mod iter {
use option::Option;
pub trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;
fn into_iter(self) -> Self::IntoIter;
}
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
}
pub mod option {
pub enum Option<T> {
Some(T),
None,
}
}
}
fn main() {}
arthur@platypus ~/G/r/gccrs (desugar-for-loops) [1]> diff root-seg.rs root-seg-broken.rs
22,27d21
< pub struct Weird<T> {
< ptr: *const T, // should be NonNull<T> but here it does not matter
< end: *const T,
< _marker: PhantomData<&T>,
< }
<
34a29,34
> }
>
> pub struct Weird<T> {
> ptr: *const T, // should be NonNull<T> but here it does not matter
> end: *const T,
> _marker: PhantomData<&T>,
I managed to reduce it to
#![feature(lang_items)]
#[lang = "sized"]
trait Sized {}
pub struct A<T>(T);
pub trait B {
type C;
}
// ------
// swap these two items
impl B for i32 {
type C = Weird<i32>;
}
pub struct Weird<T>(A<(T,)>);
// ------
trait Foo {}
impl Foo for Weird<i32> {}
fn main() {}