8eef79ca9a
Fix incorrect suggestions for E0605 Fixes #84598. Here is a simplified version of the problem presented in issue #84598: ```Rust #![allow(unused_variables)] #![allow(dead_code)] trait T { fn t(&self) -> i32; } unsafe fn foo(t: *mut dyn T) { (t as &dyn T).t(); } fn main() {} ``` The current output is: ``` error[E0605]: non-primitive cast: `*mut (dyn T + 'static)` as `&dyn T` --> src/main.rs:7:5 | 7 | (t as &dyn T).t(); | ^^^^^^^^^^^^^ invalid cast | help: borrow the value for the cast to be valid | 7 | (&t as &dyn T).t(); | ^ ``` This is incorrect, though: The cast will _not_ be valid when writing `&t` instead of `t`: ``` error[E0277]: the trait bound `*mut (dyn T + 'static): T` is not satisfied --> t4.rs:7:6 | 7 | (&t as &dyn T).t(); | ^^ the trait `T` is not implemented for `*mut (dyn T + 'static)` | = note: required for the cast to the object type `dyn T` ``` The correct suggestion is `&*t`, which I have implemented in this pull request. Of course, this suggestion will always require an unsafe block, but arguably, that's what the user really wants if they're trying to cast a pointer to a reference. In any case, claiming that the cast will be valid after implementing the suggestion is overly optimistic, as the coercion logic doesn't seem to resolve all nested obligations, i.e. the cast may still be invalid after implementing the suggestion. I have therefore rephrased the suggestion slightly ("consider borrowing the value" instead of "borrow the value for the cast to be valid"). Additionally, I have fixed another incorrect suggestion not mentioned in #84598, which relates to casting immutable references to mutable ones: ```rust fn main() { let mut x = 0; let m = &x as &mut i32; } ``` currently leads to ``` error[E0605]: non-primitive cast: `&i32` as `&mut i32` --> t5.rs:3:13 | 3 | let m = &x as &mut i32; | ^^^^^^^^^^^^^^ invalid cast | help: borrow the value for the cast to be valid | 3 | let m = &mut &x as &mut i32; | ^^^^ ``` which is obviously incorrect: ``` error[E0596]: cannot borrow data in a `&` reference as mutable --> t5.rs:3:13 | 3 | let m = &mut &x as &mut i32; | ^^^^^^^ cannot borrow as mutable ``` I've changed the suggestion to a note explaining the problem: ``` error[E0605]: non-primitive cast: `&i32` as `&mut i32` --> t5.rs:3:13 | 3 | let m = &x as &mut i32; | ^^^^^^^^^^^^^^ invalid cast | note: this reference is immutable --> t5.rs:3:13 | 3 | let m = &x as &mut i32; | ^^ note: trying to cast to a mutable reference type --> t5.rs:3:19 | 3 | let m = &x as &mut i32; | ^^^^^^^^ ``` In this example, it would have been even nicer to suggest replacing `&x` with `&mut x`, but this would be much more complex because we would have to take apart the expression to be cast (currently, we only look at its type), and `&x` could be stored in a variable, where such a suggestion would not even be directly applicable: ```rust fn main() { let mut x = 0; let r = &x; let m = r as &mut i32; } ``` My solution covers this case, too. |
||
---|---|---|
.. | ||
src | ||
Cargo.toml | ||
README.md |
For high-level intro to how type checking works in rustc, see the type checking chapter of the rustc dev guide.