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

internal error: entered unreachable code: Functions must have been inlined before checking for overflows #1327

Closed
iAmMichaelConnor opened this issue May 9, 2023 · 4 comments
Assignees
Labels
bug Something isn't working

Comments

@iAmMichaelConnor
Copy link
Collaborator

iAmMichaelConnor commented May 9, 2023

Aim

Here's a minimal example (it's not very minimal... I was doing a complicated thing, making Noir Contract very generic, which will be important).

Ultimately, I want to call a method d_method of a type D which is a concrete type, but it's returned from deep within nested generic types. Now, Noir doesn't have trait bounds, so I can't call d_method as a "method" of D. So it's actually a free function. I then adopted a trick Jake showed me: of storing d_method in a struct MethodInterface, where MethodInterface serves as an interface for all functions that D must implement.

The problem comes when trying to call this method (I think), via C.

Notation: A, B, C, D are concrete types. Generic types are labelled T_C and T_D (which are made concrete with C and D respectively).

And the comments are the names of the actual structs I'm playing with in Aztec3 code (to help me write this example code snippet).

Maybe this bug can be distilled down to a much less complicated example...

// ---

    fn new_concrete_c_over_d() -> C<D> {
        let d_method_interface = get_d_method_interface();
        C::new(d_method_interface)
    }

// ---

    // Storage
    struct A {
        b: B<C<D>>,
    }

    impl A {
        fn new() -> Self {
            A {
                b: B::new(new_concrete_c_over_d)
            }
        }
    }

// ---

    // Map<V>
    struct B<T_C> {
        new_concrete_t_c_constructor: fn()->T_C,
    }

    impl<T_C> B<T_C> {
        fn new(new_concrete_t_c_constructor: fn () -> T_C) -> B<T_C> {
            B { new_concrete_t_c_constructor }
        }

        fn get_t_c(self) -> T_C {
            let new_concrete_t_c_constructor = self.new_concrete_t_c_constructor;
            new_concrete_t_c_constructor()
        }
    }

// ---

    // Set<Note>
    struct C<T_D> {
        t_d_interface: MethodInterface<T_D>,
    }

    impl<T_D> C<T_D> {
        fn new (t_d_interface: MethodInterface<T_D>) -> Self {
            C { t_d_interface }
        }

        fn call_method_of_t_d(self, t_d: T_D) -> Field {
            let some_method_on_t_d = self.t_d_interface.some_method_on_t_d;
            some_method_on_t_d(t_d)
        }
    }

// ---

    struct MethodInterface<T_D> {
        some_method_on_t_d: fn(T_D)->Field,
    }

// ---

    // Note
    struct D {
        d: Field,
    }

    fn d_method(input: D) -> Field {
        input.d * input.d
    }

    fn get_d_method_interface() -> MethodInterface<D> {
        MethodInterface {
            some_method_on_t_d: d_method,
        }
    }  

// ---  

    fn main(input: Field) -> pub Field {
        let a: A = A::new(); // Storage
        let b: B<C<D>> = a.b; // Map<Singleton<Note>>
        let c: C<D> = b.get_t_c(); // Singleton<Note>
        let d: D = D { d: input }; // Note
        let output = c.call_method_of_t_d(d);

        output
    }

// ---

Compiler error:

The application panicked (crashed).
Message:  internal error: entered unreachable code: Functions must have been inlined before checking for overflows
Location: crates/noirc_evaluator/src/ssa/integer.rs:493

This is a bug. We may have already fixed this in newer versions of Nargo so try searching for similar issues at https://github.com/noir-lang/noir/issues/.
If there isn't an open issue for this bug, consider opening one at https://github.com/noir-lang/noir/issues/new?labels=bug&template=bug_report.yml

I was using the current master fa1af50

@iAmMichaelConnor iAmMichaelConnor added the bug Something isn't working label May 9, 2023
@github-project-automation github-project-automation bot moved this to 📋 Backlog in Noir May 9, 2023
@iAmMichaelConnor
Copy link
Collaborator Author

Slightly simplified (removing A and the bug still bites):

// ---

    fn new_concrete_c_over_d() -> C<D> {
        let d_method_interface = get_d_method_interface();
        C::new(d_method_interface)
    }

// ---

    // Map<V>
    struct B<T_C> {
        new_concrete_t_c_constructor: fn()->T_C,
    }

    impl<T_C> B<T_C> {
        fn new(new_concrete_t_c_constructor: fn () -> T_C) -> B<T_C> {
            B { new_concrete_t_c_constructor }
        }

        fn get_t_c(self) -> T_C {
            let new_concrete_t_c_constructor = self.new_concrete_t_c_constructor;
            new_concrete_t_c_constructor()
        }
    }

// ---

    // Set<Note>
    struct C<T_D> {
        t_d_interface: MethodInterface<T_D>,
    }

    impl<T_D> C<T_D> {
        fn new (t_d_interface: MethodInterface<T_D>) -> Self {
            C { t_d_interface }
        }

        fn call_method_of_t_d(self, t_d: T_D) -> Field {
            let some_method_on_t_d = self.t_d_interface.some_method_on_t_d;
            some_method_on_t_d(t_d)
        }
    }

// ---

    struct MethodInterface<T_D> {
        some_method_on_t_d: fn(T_D)->Field,
    }

// ---

    // Note
    struct D {
        d: Field,
    }

    fn d_method(input: D) -> Field {
        input.d * input.d
    }

    fn get_d_method_interface() -> MethodInterface<D> {
        MethodInterface {
            some_method_on_t_d: d_method,
        }
    }  

// ---  

    fn main(input: Field) -> pub Field {
        let b: B<C<D>> = B::new(new_concrete_c_over_d);
        let c: C<D> = b.get_t_c(); // Singleton<Note>
        let d: D = D { d: input }; // Note
        let output = c.call_method_of_t_d(d);

        output
    }

// ---

@iAmMichaelConnor
Copy link
Collaborator Author

Much more simplified:

// ---

    struct T_D_MethodInterface<T_D> {
        t_d_method: fn(T_D)->Field,
    }

// ---

    // Set<Note>
    struct C<T_D> {
        t_d_method_interface: T_D_MethodInterface<T_D>,
    }

    impl<T_D> C<T_D> {
        fn new (t_d_method_interface: T_D_MethodInterface<T_D>) -> Self {
            C { t_d_method_interface }
        }

        fn get_t_d_method_interface(self) -> T_D_MethodInterface<T_D> {
            let t_d_method_interface = self.t_d_method_interface;
            t_d_method_interface
        }
    }

// ---

    // Note
    struct D {
        d: Field,
    }

    fn d_method(input: D) -> Field {
        input.d * input.d
    }

// ---  

    fn main(input: Field) -> pub Field {
        let d_method_interface_for_setup = T_D_MethodInterface {
            t_d_method: d_method,
        };
        let c: C<D> = C::new(d_method_interface_for_setup);
        let d: D = D { d: input };

        let d_method_interface = c.get_t_d_method_interface();
        let d_method = d_method_interface.t_d_method;

        let output = d_method(d);

        output
    }

// ---

@kevaundray
Copy link
Contributor

@jfecher what is the status of this issue?

@jfecher
Copy link
Contributor

jfecher commented Jul 24, 2023

@kevaundray fixed in the new ssa

@jfecher jfecher closed this as completed Jul 24, 2023
@github-project-automation github-project-automation bot moved this from 📋 Backlog to ✅ Done in Noir Jul 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Archived in project
Development

No branches or pull requests

3 participants