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

Type inference fails without intermediate variable #5065

Closed
nventuro opened this issue May 21, 2024 · 4 comments · Fixed by #5131
Closed

Type inference fails without intermediate variable #5065

nventuro opened this issue May 21, 2024 · 4 comments · Fixed by #5131
Labels
bug Something isn't working

Comments

@nventuro
Copy link
Contributor

nventuro commented May 21, 2024

Aim

I want to rely on type inference, but in some cases it only works if I have unnecessary intermediate variables.

Bug

In the following program, concise_but_does_not_compile errors out with Expression type is ambiguous. This is fixed in verbose_but_compiles, which introduces an intermediate variable a. I'm providing zero new type information, so this looks like a bug.

struct Wrapper<T> {
    _value: T,
}

impl<T> Wrapper<T> {
    fn new(value: T) -> Self {
        Self { _value: value }
    }

    fn unwrap(self) -> T {
        self._value
    }
}

trait MyTrait {
    fn new() -> Self;
}

struct MyType {

}

impl MyTrait for MyType {
    fn new() -> Self {
        MyType {}
    }
}

fn foo<T>() -> T where T: MyTrait {
    MyTrait::new()
}

fn verbose_but_compiles() -> MyType {
    let a = Wrapper::new(foo());
    a.unwrap()
}

fn concise_but_does_not_compile() -> MyType {
    Wrapper::new(foo()).unwrap()
}

fn main() {
    let _ = verbose_but_compiles();
    let _ = concise_but_does_not_compile();
}
@nventuro nventuro added the bug Something isn't working label May 21, 2024
@sirasistant
Copy link
Contributor

Could be related to #4732 ?

@nventuro
Copy link
Contributor Author

Yes, it is definitely the same thing. I didn't see that issue before, sorry. However this is likely a better example as the code sample does not rely on external libraies to trigger the bug.

@vezenovm
Copy link
Contributor

Another workaround is to use turbofish now that Noir has the operator:

fn concise_but_does_not_compile() -> MyType {
    Wrapper::new(foo::<MyType>()).unwrap()
}

github-merge-queue bot pushed a commit that referenced this issue May 29, 2024
…5131)

# Description

## Problem\*

Resolves #5065 

Probably resolves #4732 but need to test it or have aztec team test it.

## Summary\*

When working with a program like such where `MyType` implements
`MyTrait`:
```rust
fn foo<T>() -> T where T: MyTrait {
    MyTrait::new()
}
fn concise_regression() -> MyType {
    Wrapper::new(foo()).unwrap()
}
```
We should be able to infer the return type of `foo`. We currently always
push trait constraints onto a a `Vec<(TraitConstraint, ExprId)>`. We
need to do this as we can have multiple trait constraints that need to
be handled during monomorphization due to generics. However, when
working with a method call this can cause us to store an old trait
constraint that does not necessarily apply to the expression.

The nested function call in `concise_regression` initially adds a trait
constraint simply for `foo` due to the call to `Wrapper::new(foo())` and
then another constraint for `Wrapper::new(foo()).unwrap()`. The call to
`Wrapper::new(foo())` cannot be bound to anything unless we introduce an
intermediate variable. This felt like it would be overly complex and we
just need to follow the accurate trait constraint for a function call
expression.

Taking the test in the issue and this PR we have the following trait
constraints on master for the `foo` expression:
```
TraitConstraint {
        typ: '23646 -> '23647,
        trait_id: TraitId(
            ModuleId {
                krate: Root(
                    1,
                ),
                local_id: LocalModuleId(
                    Index(
                        1,
                    ),
                ),
            },
        ),
        trait_generics: [],
    },
    TraitConstraint {
        typ: '23648 -> '23649 -> '23650 -> MyType,
        trait_id: TraitId(
            ModuleId {
                krate: Root(
                    1,
                ),
                local_id: LocalModuleId(
                    Index(
                        1,
                    ),
                ),
            },
        ),
        trait_generics: [],
    }
```
This is occurring due to an unnecessary type check on a method call's
object type. This is cause a repeated trait constraint where one has
incorrect type variables that cannot be resolved.

I have altered how MethodCall's and Call's are resolved as to avoid
repeated type checks on the object type.

## Additional Context



## Documentation\*

Check one:
- [X] No documentation needed.
- [ ] Documentation included in this PR.
- [ ] **[For Experimental Features]** Documentation to be submitted in a
separate PR.

# PR Checklist\*

- [X] I have tested the changes locally.
- [X] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.

---------

Co-authored-by: jfecher <jake@aztecprotocol.com>
@vezenovm
Copy link
Contributor

This is resolved if you want to try #4732 @sirasistant

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: Done
Development

Successfully merging a pull request may close this issue.

3 participants