rust-lang / rust-analyzer

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

[ERROR hir_ty::mir] Only tuple or closure has tuple or closure field #15090

Open Veykril opened 1 year ago

Veykril commented 1 year ago

While working on r-a itself I tend to see this spammed, I haven't figured out which part of the codebase causes this though

M4n5ter commented 8 months ago

I am currently working on a small demo project using Diesel and Axum. However, I am encountering some issues when trying to integrate Diesel. Specifically, rust-analyzer seems unable to resolve some Diesel names and lose track of the types.

In addition, I am also seeing the following error: "[ERROR hir_ty::mir] Only tuple has tuple field".

janosimas commented 7 months ago

I have the same issue with quick_error

LucaCappelletti94 commented 6 months ago

I see the same issue working with Diesel and Actix, maybe it has something to do with all of those macros from Diesel?

adwhit commented 6 months ago

I can reproduce with the following

impl Bork {
    fn f((x, y): T) {}
}

Note that Bork need not exist for the error to appear. It is specifically the pattern matching an unknown type within the signature that seems to cause the error.

Backtrace ``` Panic context: > fetch_native_diagnostics thread 'Worker' panicked at crates/hir-ty/src/mir.rs:185:21: internal error: entered unreachable code: Only tuple has tuple field stack backtrace: 0: rust_begin_unwind at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5 1: core::panicking::panic_fmt at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14 2: core::panicking::unreachable_display 3: hir_ty::mir::ProjectionElem::projected_ty 4: hir_ty::mir::borrowck::moved_out_of_ref::{{closure}} 5: hir_ty::mir::borrowck::moved_out_of_ref 6: hir_ty::mir::borrowck::borrowck_query::{{closure}} 7: hir_ty::mir::borrowck::all_mir_bodies 8: hir_ty::mir::borrowck::borrowck_query 9: salsa::Cycle::catch 10: salsa::derived::slot::Slot::execute 11: salsa::derived::slot::Slot::read 12: as salsa::plumbing::QueryStorageOps>::fetch 13: ::borrowck::__shim 14: ::borrowck 15: hir::DefWithBody::diagnostics 16: hir::Module::diagnostics 17: ide_diagnostics::diagnostics 18: salsa::Cancelled::catch 19: ide::Analysis::with_db 20: ide::Analysis::diagnostics 21: core::ops::function::impls:: for &mut F>::call_mut 22: as alloc::vec::spec_from_iter::SpecFromIter>::from_iter 23: rust_analyzer::diagnostics::fetch_native_diagnostics 24: core::ops::function::FnOnce::call_once{{vtable.shim}} note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. ```

Edit: In fact it can be reduced to just

fn f((x, y): T) {}
adwhit commented 6 months ago

Investigated a little bit. Here is a way to make a similar error:

enum Foo {
    Bar { x: i32 },
}

fn f(Foo::Bar { x }: T) {}

Error: internal error: entered unreachable code: Only adt has field, found {error}\n.

And this:

fn f(&x: T) {}

Error: internal error: entered unreachable code: Overloaded deref on type {unknown} is not a projection\n

In general, the error-handling in this block is off: https://github.com/rust-lang/rust-analyzer/blob/2b7b44bf27a7635eded9aa53678acb2c4e25063e/crates/hir-ty/src/mir.rs#L154-L227. It assumes type errors cannot happen, but evidently they can.

Veykril commented 6 months ago

We might wanna set a flag for InferenceResult whether errors happened and then just error out in mir lowering if that is the case

adwhit commented 6 months ago

Here is another test case that, unlike the others, is actually valid code:

struct Foo<T> {
    l: T,
    r: T,
}

trait Trait {
    type State;
    fn f(_: Self::State) -> Self;
}

impl<T> Trait for Foo<T> {
    type State = (T, T);

    fn f(state: Self::State) -> Self {
        Self {
            l: state.0,
            r: state.1,
        }
    }
}

It has trouble detecting that Self::State is in fact a tuple.

EndilWayfare commented 6 months ago

It is specifically the pattern matching an unknown type within the signature that seems to cause the error.

Backtrace Edit: In fact it can be reduced to just

fn f((x, y): T) {}

Aww man, that's totally why this slams axum and diesel, lmao. Extractors and SQL rows. I have a lot of tuple destructuring in my data layer, so at least now I know why my inference has ground to a crawl.

I've been meaning to get up to speed on rust-analyzer internals and dip my toes into contributing. How crazy of a first issue would this be to jump into, do you think?

Veykril commented 6 months ago

Hmm, fwiw this should only affect MIR building for the function so at worst you'll miss out on some diagnostics there.

The simple fix would be to skip mir building if we encounter any sort of type mismatches as said here https://github.com/rust-lang/rust-analyzer/issues/15090#issuecomment-1985638015 which shouldn't be too difficult. It's basically adding a bool field to InferenceResult, and check that in lower_to_mir and bail out if its set.

Dushistov commented 2 months ago

I have the same issue.

I edit

fn f(arg: (usize, bool)) {}

remove arg and add (index, fla and rust-analyzer crash on

fn f((index,fla: (usize, bool)) {}

panic backtrace:

thread 'Worker' panicked at crates/hir-ty/src/mir.rs:185:21:
internal error: entered unreachable code: Only tuple has tuple field
stack backtrace:
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::unreachable_display
   3: hir_ty::mir::ProjectionElem<V,T>::projected_ty
   4: hir_ty::mir::borrowck::moved_out_of_ref::{{closure}}
   5: hir_ty::mir::borrowck::moved_out_of_ref
   6: hir_ty::mir::borrowck::borrowck_query::{{closure}}
   7: hir_ty::mir::borrowck::all_mir_bodies
   8: hir_ty::mir::borrowck::borrowck_query
   9: salsa::Cycle::catch
  10: salsa::derived::slot::Slot<Q,MP>::execute
  11: salsa::derived::slot::Slot<Q,MP>::read
  12: <salsa::derived::DerivedStorage<Q,MP> as salsa::plumbing::QueryStorageOps<Q>>::fetch
  13: <DB as hir_ty::db::HirDatabase>::borrowck::__shim
  14: <DB as hir_ty::db::HirDatabase>::borrowck
  15: hir::DefWithBody::diagnostics
  16: hir::ModuleDef::diagnostics
  17: hir::Module::diagnostics
  18: ide_diagnostics::diagnostics
  19: salsa::Cancelled::catch
  20: ide::Analysis::diagnostics
  21: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut
  22: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter
  23: rust_analyzer::diagnostics::fetch_native_diagnostics
  24: core::ops::function::FnOnce::call_once{{vtable.shim}}
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

rustc --version rustc 1.80.0-beta.4 (64a1fe671 2024-06-21)

rust-analyzer --version rust-analyzer 0.0.0 (cae997e338 2024-07-03)

davidbarsky commented 1 week ago

I've found a more minimal reproduction. Going from fn f(arg: (usize, bool)) {} to fn f((arg: (usize, bool)) {} is enough to crash rust-analyzer with "internal error: entered unreachable code: Only tuple has tuple field".