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 error when accessing field #50692

Closed
df5602 opened this issue May 12, 2018 · 6 comments
Closed

Type inference error when accessing field #50692

df5602 opened this issue May 12, 2018 · 6 comments

Comments

@df5602
Copy link

df5602 commented May 12, 2018

I was advised to open an issue here, so here goes:

I stumbled upon a strange compile error today, that I have minimized to the following example (Playground):

#[derive(Copy, Clone, Debug)]
struct Element {
    next: Option<usize>,
}

fn main() {
    let array = [Element { next: None }; 16];
    let number: usize = 42;
    let mut option = None;

    match option {
        Some(n) => {
            // This alone compiles
            let bar = array[n];
            println!("Number is {:?}", bar);

            // The following doesn't compile:

            // error[E0282]: type annotations needed
            //  --> src/main.rs:19:23
            //    |
            // 19 |             let foo = array[n].next;
            //    |                       ^^^^^^^^^^^^^ cannot infer type for `_`

            let foo = array[n].next;
            println!("Number is {:?}", foo);
        }
        None => option = Some(number),
    }

    println!("{:?}", option);
}

What's strange is that when I add a purposefully wrong type annotation like this:

let bar: bool = array[n];

the compiler correctly recognizes that bool is the wrong type and even tells me the correct type:

error[E0271]: type mismatch resolving `<usize as std::slice::SliceIndex<[Element]>>::Output == bool`
  --> src/main.rs:14:29
   |
14 |             let bar: bool = array[n];
   |                             ^^^^^^^^ expected struct `Element`, found bool
   |
   = note: expected type `Element`
              found type `bool`

However, as soon as I try to access a field, type inference fails. (Basically it knows that array[n] is of type Element, but later cannot infer the type of array[n].next.)

Is this a known limitation of type inference?

(EDIT: I'm aware that I can get rid of the compile error by adding a type annotation to the declaration of option. I'm just surprised by the behaviour of type inference in this example..)

@KamilaBorowska
Copy link
Contributor

KamilaBorowska commented May 12, 2018

Simplified example:

fn main() {
    let array = [0; 16];
    let mut option = None;
    if let Some(n) = option {
        array[n];
        array[n].to_le();
    }
}

Interestingly, this can be workarounded in the provided example by having None branch in match as first.

@leoyvens
Copy link
Contributor

leoyvens commented May 12, 2018

What is happening is that because n is not known, then array[n] is not known and therefore you cannot access a field. This is a well known limitation. The error message could be better at indicating that type checking could not proceed.

@df5602
Copy link
Author

df5602 commented May 12, 2018

But array[n] is known in this case, otherwise the line with bar wouldn't (or shouldn't) compile. It's only when I try to additionally access a field (the line with foo), that the compiler suddenly unlearns a fact that it knew just a few lines above..

@leoyvens
Copy link
Contributor

leoyvens commented May 12, 2018

To clarify, array[n] will only become known a few lines below at option = Some(number) where the type of n becomes known. If you insert a field access then the compile "refuses" to reach the information it would need, this is a known limitation. What do you think would be a good note on the error to reflect this? I'm thinking: "note: type checking cannot proceed past this point".

@df5602
Copy link
Author

df5602 commented May 12, 2018

Ah ok, I think I (sort of) get it now.

To be honest, I don't think how type inference works exactly needs to be mentioned in the error. (Basically, if it cannot infer the types in line X, I have no expectations for it to continue beyond that point.)

What cost me some time, because it wasn't immediately obvious to me (the real code was a little bit more complicated than this minimal example), was that at first, I wasn't able to trace the error back to a specific variable. It would have helped immensely if the error message had been something along the lines of "cannot infer type of n". In that case I would probably have been able to trace it back to the declaration of option much quicker.

leoyvens added a commit to leoyvens/rust that referenced this issue May 13, 2018
This PR improves the span of eager resolution type errors referring to indexing and field access to use the base span rather than the whole expression.

Also a note "Type must be known at this point." is added to where we at some point in the past emitted the "type must be known at this context" error, so that early failures can be differentiated and will hopefully be less surprising.

Fixes rust-lang#50692 (or at least does the best we can for the moment)

r? @estebank
@leoyvens
Copy link
Contributor

leoyvens commented May 13, 2018

That's a good idea, but I think it would be complicated to implement. Hopefully with the chalk integration we will be able to make progress on the underlining issue. For now, I've changed the message:

error[E0282]: type annotations needed
 |
 |             let foo = array[n].next;
 |                       ^^^^^^^^^^^^^ cannot infer type for `_`

To:

error[E0282]: type annotations needed
 |
 |             let foo = array[n].next;
 |                       ^^^^^^^^ cannot infer type for `_`
 | note: type must be known at this point

Hopefully the corrected span and the note will make things a bit less confusing.

kennytm added a commit to kennytm/rust that referenced this issue May 14, 2018
…n-error-message, r=estebank

Improve eager type resolution error message

This PR improves the span of eager resolution type errors referring to indexing and field access to use the base span rather than the whole expression.

Also a "note: type must be known at this point" is added where in the past we emitted the "type must be known at this context" error, so that early failures can be differentiated and will hopefully be less surprising.

Fixes rust-lang#50692 (or at least does the best we can for the moment)

r? @estebank
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue May 15, 2018
…n-error-message, r=estebank

Improve eager type resolution error message

This PR improves the span of eager resolution type errors referring to indexing and field access to use the base span rather than the whole expression.

Also a "note: type must be known at this point" is added where in the past we emitted the "type must be known at this context" error, so that early failures can be differentiated and will hopefully be less surprising.

Fixes rust-lang#50692 (or at least does the best we can for the moment)

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

No branches or pull requests

3 participants