gccrs icon indicating copy to clipboard operation
gccrs copied to clipboard

Weird root segment type resolution issue depending on order of items?

Open CohenArthur opened this issue 1 year ago • 1 comments

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>,

CohenArthur avatar Mar 06 '24 12:03 CohenArthur

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() {}

powerboat9 avatar Mar 07 '24 18:03 powerboat9