Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
CohenArthur opened this issue Mar 6, 2024 · 1 comment
Open

Comments

@CohenArthur
Copy link
Member

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 CohenArthur added the bug label Mar 6, 2024
@powerboat9
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants