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

Usage of a trait method inside of another trait impl results in resolver errors #4943

Open
TomAFrench opened this issue Apr 29, 2024 · 5 comments
Labels
bug Something isn't working

Comments

@TomAFrench
Copy link
Member

TomAFrench commented Apr 29, 2024

Aim

I would like to use trait methods inside the impls of other traits for one of my structs.

Expected Behavior


impl From<u64> for MyU128 {
    fn from(value: u64) -> MyU128 {
       MyU128::from_u64s_le(value, 0)
    }
}

impl From<u32> for MyU128 {
    fn from(value: u32) -> MyU128 {
       MyU128::from(value as u64)
    }
}

This usage of traits implemented on a type in other trait impls for that type should be valid Noir.

Bug

The example program doesn't compile

use dep::std::convert::From;
use dep::std::field;

struct MyU128 {
    lo: Field,
    hi: Field,
}

impl MyU128 {
    pub fn from_u64s_le(lo: u64, hi: u64) -> MyU128 {
        // in order to handle multiplication, we need to represent the product of two u64 without overflow
        assert(field::modulus_num_bits() as u32 > 128);
        MyU128 { lo: lo as Field, hi: hi as Field }
    }
}

impl From<u64> for MyU128 {
    fn from(value: u64) -> MyU128 {
       MyU128::from_u64s_le(value, 0)
    }
}

impl From<u32> for MyU128 {
    fn from(value: u32) -> MyU128 {
       MyU128::from(value as u64)
    }
}

fn main(mut x: u64) {
    let mut small_int = MyU128::from(x);
    assert(small_int.lo == x as Field);
    assert(MyU128::from(3).lo == 3);
}

instead we get the error messages

error: Trait plain::Foo not found
   ┌─ /home/tom/Programming/aztec/noir/test_programs/execution_success/trait_call_trait_method/src/main.nr:29:6
   │
29 │ impl Foo for MyU128 { 
   │      ---
   │

error: Could not resolve 'from' in path
   ┌─ /home/tom/Programming/aztec/noir/test_programs/execution_success/trait_call_trait_method/src/main.nr:36:33
   │
36 │     let mut small_int = MyU128::from(x);
   │                                 ----
   │

error: Could not resolve 'from' in path
   ┌─ /home/tom/Programming/aztec/noir/test_programs/execution_success/trait_call_trait_method/src/main.nr:38:20
   │
38 │     assert(MyU128::from(3).lo == 3);
   │                    ----
   │

error: Could not resolve 'from' in path
   ┌─ /home/tom/Programming/aztec/noir/test_programs/execution_success/trait_call_trait_method/src/main.nr:25:16
   │
25 │        MyU128::from(value as u64)
   │                ----
   │

error: Could not resolve 'from' in path
   ┌─ /home/tom/Programming/aztec/noir/test_programs/execution_success/trait_call_trait_method/src/main.nr:31:17
   │
31 │         MyU128::from(other)
   │                 ----
   │

Aborting due to 5 previous errors

Commenting out the latter 2 trait impls removes all compilation errors (including the errors which occur inside the main function)

To Reproduce

  1. Attempt to compile the above code

Project Impact

Nice-to-have

Impact Context

Nice to have as we can often pull the implementation out of the trait being called and then delegate to that.

Workaround

None

Workaround Description

No response

Additional Context

No response

Installation Method

Compiled from source

Nargo Version

No response

NoirJS Version

No response

Would you like to submit a PR for this Issue?

None

Support Needs

No response

@jfecher
Copy link
Contributor

jfecher commented Apr 29, 2024

Is the impl Foo with no Foo defined significant here?

Looks like there's a lot of missing code from this snippet in general since MyU128 also isn't defined

@TomAFrench
Copy link
Member Author

TomAFrench commented Apr 29, 2024

Ah apologies, there's a full program below. I was trying to draw attention to the impls using each other but, yeah, it's confusing atm.

Edit: ah, even that's missing the snippet.

@TomAFrench
Copy link
Member Author

TomAFrench commented Apr 29, 2024

I've updated the main post. Looks like the Foo was failing due to the trait just not existing but I didn't notice as it manifests the same way as the issue with From.

@jfecher
Copy link
Contributor

jfecher commented Apr 29, 2024

I recreated this as:

use dep::std::convert::From;
use dep::std::field;

struct MyU128 {
    lo: Field,
    hi: Field,
}

impl MyU128 {
    fn from_u64s_le(_a: u64, _b: u64) -> Self {
        Self {
            lo: _a as Field, hi: _b as Field,
        }
    }
}

impl From<u64> for MyU128 {
    fn from(value: u64) -> MyU128 {
       MyU128::from_u64s_le(value, 0)
    }
}

impl From<u32> for MyU128 {
    fn from(value: u32) -> MyU128 {
       MyU128::from(value as u64)
    }
}

// impl Foo for MyU128 { 
//     fn foo(self, other: u8) -> MyU128 { 
//         MyU128::from(other)
//     } 
// }

fn main(mut x: u64) {
    let mut small_int = MyU128::from(x);
    assert(small_int.lo == x as Field);
    assert(MyU128::from(3).lo == 3);
}

and am getting the relevant from errors

@jfecher
Copy link
Contributor

jfecher commented Apr 29, 2024

Ah, I remember why this is happening.

If there are multiple generic impls implemented on the same type we add neither to the type namespace currently since it'd lead to a name conflict between one from and another. The workaround for now is to use the trait static function syntax From::from(..)

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
Status: 📋 Backlog
Development

No branches or pull requests

2 participants