Deref coercions do not work with blocks

c4757af
Opened by Barosl Lee at 2024-12-21 05:10:29

It seems that the compiler handles a block differently when coercing a value.

fn f(_: &str) {}

fn main() {
    let x = "Akemi Homura".to_owned();

    f(&x); // OK
    f(&(x)); // OK
    f(&{x}); // Error
}

RFC 401 says that a block with type U is also a target for coercion, so I think this behavior is a bug.

blocks, if a block has type U, then the last expression in the block (if it is not semicolon-terminated) is a coercion site to U. This includes blocks which are part of control flow statements, such as if/else, if the block has a known type.

Also, the compiler seems to be able to coerce blocks using some "trivial" rules (e.g. &mut T -> &T).

fn f(_: &i32) {}

fn main() {
    let x = &mut 42;

    f(x); // OK
    f((x)); // OK
    f({x}); // OK
}

So I guess this is more likely a problem of auto-deref.

  1. CC @nrc

    Aria Desires at 2015-07-11 23:03:42

  2. As some users have discovered, {x}.item can be used to force a x: &mut X to move instead of reborrow. Is that related? We might not be allowed to break that.

    bluss at 2015-07-12 08:45:57

  3. I suspect this is something specific to deref coercions. I think it is 'just a bug', but I don't know how easy it is to fix.

    Nick Cameron at 2015-07-12 22:46:45

  4. This blocks usage of try! together with deref coercions if I understand this bug correctly:

    let _: &Path = &try!(env::current_dir()); fails to compile.

    Tobias Bucher at 2015-08-20 11:40:24

  5. @tbu- Yup, actually this issue was found by a Stack Overflow question that tried the same thing.

    Barosl Lee at 2015-08-21 06:46:13

  6. There is also this rust-users thread with a very similar problem.

    llogiq at 2015-09-19 13:42:09

  7. triage: I-nominated

    Nick Cameron at 2015-09-21 21:18:32

  8. triaged because it is such an annoying bug. Recommend p-medium.

    Nick Cameron at 2015-09-21 21:19:09

  9. cc @eddyb

    Niko Matsakis at 2015-10-01 20:17:30

  10. triage: P-medium

    Niko Matsakis at 2015-10-01 20:18:27

  11. It would be very helpful to point out the error, which is:

    <anon>:8:9: 8:10 error: mismatched types:
     expected `str`,
        found `collections::string::String`
    (expected str,
        found struct `collections::string::String`) [E0308]
    <anon>:8     f(&{x}); // Error
                     ^
    

    So the problem could be that str propagated through the block to x, despite being unsized. As blocks are always rvalues, maybe the "expected type" propagation doesn't deal with unsized values being mere hints in the block case?

    Eduard-Mihai Burtescu at 2015-10-03 17:28:02

  12. Update: That was dumb of me: I did not realize this only ever happens with str. Of course it does, because I never implemented it.

    Eduard-Mihai Burtescu at 2016-02-14 13:23:16

  13. This issue should be reopened:

    fn f(_: &i32) {}
    
    fn main() {
        let x = Box::new(1i32);
    
        f(&x); // OK
        f(&(x)); // OK
        f(&{x}); // Error
    }
    

    Donough Liu at 2021-04-04 14:41:13

  14. I should've renamed the title of this issue, I believe (based on my comments in this thread) that this issue was specifically about str not working the same was [T].

    I doubt your example ever worked, because the block gets i32 as the expected type and that is Sized, so there's no way to rule it out as the type of the block.

    Eduard-Mihai Burtescu at 2021-04-30 11:33:00