rust-lang / rust-analyzer

A Rust compiler front-end for IDEs
https://rust-analyzer.github.io/
Apache License 2.0
14.06k stars 1.56k forks source link

rust-analyzer emits type error where rustc compiles fine #15984

Open cdoepmann opened 9 months ago

cdoepmann commented 9 months ago

rust-analyzer version: rust-analyzer version: 0.3.1748-standalone

rustc version: rustc 1.74.0 (79e9716c9 2023-11-13)

src/main.rs:

use crossbeam_channel::bounded;

fn main() {
    let (sender, _) = bounded(2);
    let value = 0usize;

    crossbeam_channel::select! {
        send(sender, value) -> _ => { todo!(); }
    };
}

Cargo.toml:

[package]
name = "bugtest"
version = "0.1.0"
edition = "2021"

[dependencies]
crossbeam-channel = "0.5.8"

This example compiles fine with rustc/cargo, but rust-analyzer emits the following error at the macro invocation: expected &dyn SelectHandle, found &Sender<usize>

The error vanishes, if you add an explicit type during the channel construction: let (sender, _) = bounded::<usize>(2);

Since rustc compiles this fine, rust-analyzer should also accept it.

Austaras commented 8 months ago

Minimal reproduction

struct Sender<T> {
    inner: [T; 0],
}

impl<T> Sender<T> {
    fn send(&self, msg: T) {}
}

trait SelectHandle {}

impl<T> SelectHandle for Sender<T> {}

impl<T: SelectHandle> SelectHandle for &T {}

fn foo() {
    let sender = Sender { inner: [] };

    let _handle: &dyn SelectHandle = &sender;

    sender.send(0_usize);
}
Austaras commented 8 months ago

So the problem here is r-a created a new type var '0 in

let sender = Sender { inner: [] };

for Sender<T>, then try to check if &Sender<'0> can be coerced to &dyn SelectHandle. So chalk would try to resolve Sender<'0>: SelectHandle, but fails because it doesn't know if '0 is sized or not.

The solution maybe is to explicitly tell chalk that '0 is Sized from the Sized bound of struct Sender, or maybe chalk could somehow infer that itself. But I don't know chalk enough to decide if it's possible.

This is quite similar to #11847.

Austaras commented 8 months ago

A symmetric false positive

struct Sender<T> { val: [T; 0] }

impl<T> Sender<T> {
    fn send(&self, msg: T) {}
}

trait Foo {}

fn u<T: Foo>(sender: &Sender<T>) {}

fn foo() {
    let sender = Sender { val: []};

    u(&sender);

    sender.send(0_usize);
}