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

Methods and associated functions not found on types having nested generic type arguments #6825

Open
ironcev opened this issue Jan 9, 2025 · 0 comments · May be fixed by #6827
Open

Methods and associated functions not found on types having nested generic type arguments #6825

ironcev opened this issue Jan 9, 2025 · 0 comments · May be fixed by #6827
Assignees
Labels
bug Something isn't working compiler: frontend Everything to do with type checking, control flow analysis, and everything between parsing and IRgen

Comments

@ironcev
Copy link
Member

ironcev commented Jan 9, 2025

E.g.:

fn foo<T>() {
    let o: Option<Option<T>> = None;
    let _ = o.is_none();
    //        ^^^^^^^ No method "is_none(Option<Option<T>>)" found for type "Option<Option<T>>".
    
    // Note that if we call the method without the '.' syntax it will be found.
    let _ = Option::is_none(o);
}

Here is a more comprehensive minimal repro that shows that the issue happens when the generic argument is itself generic. It also happens regardless if the final unknown generic is coming from the type of function/method definition:

library;

enum MyOption<T> {
    Some: T,
    None: (),
}

impl<T> MyOption<T> {
    fn new() -> Self {
        Self::None
    }

    fn is_none(self) -> bool {
        true
    }
}

fn generic_arg_in_function_method_call<T>() {
    let o: MyOption<u64> = MyOption::None;
    let _ = o.is_none(); // Ok.
    
    let o: MyOption<MyOption<u64>> = MyOption::None;
    let _ = o.is_none(); // Ok.

    let o: MyOption<T> = MyOption::None;
    let _ = o.is_none(); // Ok.
    
    let o: MyOption<MyOption<T>> = MyOption::None;
    // let _ = o.is_none();
    //           ^^^^^^^ No method "is_none(MyOption<MyOption<T>>)" found for type "MyOption<MyOption<T>>".
    
    let _ = MyOption::is_none(o); // Ok ;-)
}

fn generic_arg_in_function_associated_function_call<T>() {
    let _ = MyOption::<u64>::new(); // Ok.
    let o: MyOption<u64> = MyOption::new(); // Ok.
    
    let _ = MyOption::<MyOption<u64>>::new(); // Ok.
    let o: MyOption<MyOption<u64>> = MyOption::new(); // Ok.

    let _ = MyOption::<T>::new(); // Ok.
    let o: MyOption<T> = MyOption::new(); // Ok.
    
    let _ = MyOption::<MyOption<T>>::new();
    //                               ^^^ No method "new()" found for type "MyOption<MyOption<T>>".
    
    // // let o: MyOption<MyOption<T>> = MyOption::new();
    //                                ^^^^^^^^^^^^^^^ Mismatched types.
    // expected: MyOption<MyOption<T>>
    // found:    MyOption<T>.
    // help: Variable declaration's type annotation does not match up with the assigned expression's type.
}

struct S<T> { }

impl<T> S<T> {
    fn generic_arg_in_type() {
        let o: MyOption<u64> = MyOption::None;
        let _ = o.is_none(); // Ok.
        
        let o: MyOption<MyOption<u64>> = MyOption::None;
        let _ = o.is_none(); // Ok.
    
        let o: MyOption<T> = MyOption::None;
        let _ = o.is_none(); // Ok.
        
        let o: MyOption<MyOption<T>> = MyOption::None;
        // let _ = o.is_none();
        //           ^^^^^^^ No method "is_none(MyOption<MyOption<T>>)" found for type "MyOption<MyOption<T>>".
        
        let _ = MyOption::is_none(o); // Ok ;-)
    }
}

pub fn main() {
    generic_arg_in_function_method_call::<(())>();
    S::<()>::generic_arg_in_type();

    generic_arg_in_function_associated_function_call::<()>();
}

The issue is also reproducible on the current mainnet version 0.66.5.

Here are some real-life examples using types from the standard library that fail to compile.

No method new found for type StorageKey

No method is_none found for type Option

@ironcev ironcev added bug Something isn't working compiler: frontend Everything to do with type checking, control flow analysis, and everything between parsing and IRgen labels Jan 9, 2025
@esdrubal esdrubal self-assigned this Jan 9, 2025
esdrubal added a commit that referenced this issue Jan 10, 2025
The unify_checker was returning false when comparing MyOption<T> with T.
And filter_by_type_inner type substitution when adding methods from MyOption<T>
to MyOption<MyOption<T>> was replacing MyOption<T> in its own type, ending up
by inserting into type MyOption<MyOption<MyOption<T>>> instead of MyOption<MyOption<T>>.

Fixes #6825
@esdrubal esdrubal linked a pull request Jan 10, 2025 that will close this issue
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working compiler: frontend Everything to do with type checking, control flow analysis, and everything between parsing and IRgen
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants