rust-analyzer icon indicating copy to clipboard operation
rust-analyzer copied to clipboard

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

Open Veykril opened this issue 2 years ago • 3 comments

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

Veykril avatar Jun 19 '23 13:06 Veykril

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".

M4n5ter avatar Jan 18 '24 13:01 M4n5ter

I have the same issue with quick_error

janosimas avatar Feb 06 '24 12:02 janosimas

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

LucaCappelletti94 avatar Feb 23 '24 17:02 LucaCappelletti94

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<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::Module::diagnostics
  17: ide_diagnostics::diagnostics
  18: salsa::Cancelled::catch
  19: ide::Analysis::with_db
  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.

Edit: In fact it can be reduced to just

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

adwhit avatar Mar 08 '24 00:03 adwhit

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.

adwhit avatar Mar 08 '24 12:03 adwhit

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

Veykril avatar Mar 08 '24 12:03 Veykril

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.

adwhit avatar Mar 08 '24 14:03 adwhit

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?

EndilWayfare avatar Mar 13 '24 00:03 EndilWayfare

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.

Veykril avatar Mar 13 '24 08:03 Veykril

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)

Dushistov avatar Jul 06 '24 05:07 Dushistov