Skip to content

overflowing_literals error is confusing because of type inference #79744

Description

@shreepads

While experimenting with the Rust By Example playground on the Inference section at https://doc.rust-lang.org/stable/rust-by-example/types/inference.html I came across what I believe is an error in the error produced by the compiler.

I do not expect this example to work but the error literal out of range for 'i8' is reported against line 4 let e2 = 230; which is a perfectly valid statement. The problem is lower down where two different types are pushed onto the same Vector but possibly due to the way the inference engine works this is being incorrectly reported against line 4. If I comment out the line vec.push(e2);, the example works fine, apart from a warning: unused variable: 'e2'.

Code

fn main() {
    // Because of the annotation, the compiler knows that `elem` has type i8.
    let elem = 6i8;
    let e2 = 230;

    // Create an empty vector (a growable array).
    let mut vec = Vec::new();
    // At this point the compiler doesn't know the exact type of `vec`, it
    // just knows that it's a vector of something (`Vec<_>`).

    // Insert `elem` in the vector.
    vec.push(e2);
    vec.push(elem);
    // Aha! Now the compiler knows that `vec` is a vector of `u8`s (`Vec<u8>`)
    // TODO ^ Try commenting out the `vec.push(elem)` line

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

Meta

rustc --version --verbose: I am unable to determine the exact compiler version in the Rust By Example playground. I have run the same example on my Fedora 32 Workstation machine and with the same result. The rustc version details for this machine are as follows

rustc 1.48.0
binary: rustc
commit-hash: unknown
commit-date: unknown
host: x86_64-unknown-linux-gnu
release: 1.48.0
LLVM version: 10.0

Error output

   Compiling playground v0.0.1 (/playground)
error: literal out of range for `i8`
 --> src/main.rs:4:14
  |
4 |     let e2 = 230;
  |              ^^^
  |
  = note: `#[deny(overflowing_literals)]` on by default
  = note: the literal `230` does not fit into the type `i8` whose range is `-128..=127`

error: aborting due to previous error

error: could not compile `playground`

To learn more, run the command again with --verbose.
Backtrace Sorry I don't know exactly how to provide this.

<backtrace>

Activity

  1. added
    C-bugCategory: This is a bug.
    I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Dec 5, 2020
  2. jonas-schievink commented on Dec 5, 2020

    @jonas-schievink
    Contributor

    e2 also has type i8, because you push it onto the same Vec as elem, so the error message is correct – the literal is out of range for the target type i8

  3. shreepads commented on Dec 5, 2020

    @shreepads
    Author

    While that is true (and as I mentioned, I do not expect this to work) the problem is the error reported by the compiler doesn't help the user resolve the problem. In a small example like this it's easy to see where the problem lies but in a larger one the compiler error would send the user in the wrong direction.

  4. jonas-schievink commented on Dec 5, 2020

    @jonas-schievink
    Contributor

    okay, marking as a diagnostics enhancement

  5. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    and removed
    C-bugCategory: This is a bug.
    I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
    on Dec 5, 2020
  6. added
    E-hardCall for participation: Hard difficulty. Experience needed to fix: A lot.
    on Dec 5, 2020
  7. camelid commented on Dec 5, 2020

    @camelid
    Member

    I'm guessing this would be hard to implement since we'd need to somehow track the spot(s) that caused us to infer a particular type.

  8. 5 remaining items

  9. camelid commented on Dec 6, 2020

    @camelid
    Member

    Reposting my idea from Zulip:

    Perhaps we could store something in the TyCtxt or Sess that maps every AST node to its "inference source". There would be a struct InferenceSource that would hold the spans that caused this node to be inferred to be a particular type:

    pub struct InferenceSource {
        pub source_spans: Vec<Span>,
    }

    Over time we could add more fields if we wanted more detailed diagnostics.

  10. camelid commented on Dec 6, 2020

    @camelid
    Member

    I'm not sure how feasible that is, but seems potentially possible.

  11. camelid commented on Dec 6, 2020

    @camelid
    Member

    One thing we'd need to figure out is when and how much to show of the inference-source stack. In some situations, it may not be helpful, and in others it may be too much information.

  12. shreepads commented on Dec 6, 2020

    @shreepads
    Author

    In the first example, all the compiler knows is that e2 is an integer, so when it sees you push it into what it's inferred to be a Vec<i8>, it says "OK! I guess e2 must be an i8".

    This had me confused for a bit as well, i.e. I'm first pushing e2 onto the Vector so I thought it would infer it to be Vec<i32> and then complain about adding the i8 but I guess the inference engine builds some kind of constraint model and uses the i8 even though it is pushed second because the e2 literal is not explicitly typed.

    I experimented with let e2 = 2300; and let e2 = 2300i16; and in the first case it again reports literal out of range for 'i8' while in the second it reports mismatched types so I think I understand the inference model a little better!

    One thing we'd need to figure out is when and how much to show of the inference-source stack. In some situations, it may not be helpful, and in others it may be too much information.

    From an end-user perspective I couldn't follow much of what you said but if the diagnostic was to point to the line where the element was pushed (or otherwise used in a manner that causes a type mismatch) and not where it has its value set, that would be better.

  13. scottmcm commented on Dec 11, 2020

    @scottmcm
    Member

    I experimented with let e2 = 2300; and let e2 = 2300i16;

    I think this suggests an inexpensive way forward for a diagnostic here: suggest that they add a suffix and recompile. For example, it could see the 230 and say something like "help: if you're unsure why it was inferred as i8, try changing it to 230_u8 and seeing where you get a type error". (Of course, if it's already suffixed, like 300_u8, then it shouldn't suggest that.)

  14. camelid commented on Dec 11, 2020

    @camelid
    Member

    That’s a good idea! :)

  15. self-assigned this
    on Dec 11, 2020
  16. added
    E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
    E-mediumCall for participation: Medium difficulty. Experience needed to fix: Intermediate.
    and removed
    E-hardCall for participation: Hard difficulty. Experience needed to fix: A lot.
    E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
    on Dec 11, 2020
  17. added 2 commits that reference this issue on Feb 16, 2021
    625410f
    e19d6fc
  18. added a commit that references this issue on Feb 17, 2021
    ec00784
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-inferenceArea: Type inferenceC-enhancementCategory: An issue proposing an enhancement or a PR with one.E-mediumCall for participation: Medium difficulty. Experience needed to fix: Intermediate.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions