Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Veykril opened this issue Jun 19, 2023 · 18 comments
Open

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

Veykril opened this issue Jun 19, 2023 · 18 comments
Labels
A-mir C-bug Category: bug

Comments

@Veykril
Copy link
Member

Veykril commented Jun 19, 2023

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 Veykril added C-bug Category: bug A-mir labels Jun 19, 2023
@M4n5ter
Copy link

M4n5ter commented Jan 18, 2024

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
Copy link

I have the same issue with quick_error

@LucaCappelletti94
Copy link

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

@adwhit
Copy link

adwhit commented Mar 8, 2024

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
Copy link

adwhit commented Mar 8, 2024

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:

match self {
ProjectionElem::Deref => match &base.kind(Interner) {
TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
TyKind::Adt(adt, subst) if is_box(db, adt.0) => {
subst.at(Interner, 0).assert_ty_ref(Interner).clone()
}
_ => {
never!("Overloaded deref on type {} is not a projection", base.display(db));
TyKind::Error.intern(Interner)
}
},
ProjectionElem::Field(Either::Left(f)) => match &base.kind(Interner) {
TyKind::Adt(_, subst) => {
db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
}
ty => {
never!("Only adt has field, found {:?}", ty);
TyKind::Error.intern(Interner)
}
},
ProjectionElem::Field(Either::Right(f)) => match &base.kind(Interner) {
TyKind::Tuple(_, subst) => subst
.as_slice(Interner)
.get(f.index as usize)
.map(|x| x.assert_ty_ref(Interner))
.cloned()
.unwrap_or_else(|| {
never!("Out of bound tuple field");
TyKind::Error.intern(Interner)
}),
_ => {
never!("Only tuple has tuple field");
TyKind::Error.intern(Interner)
}
},
ProjectionElem::ClosureField(f) => match &base.kind(Interner) {
TyKind::Closure(id, subst) => closure_field(*id, subst, *f),
_ => {
never!("Only closure has closure field");
TyKind::Error.intern(Interner)
}
},
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => {
match &base.kind(Interner) {
TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
_ => {
never!("Overloaded index is not a projection");
TyKind::Error.intern(Interner)
}
}
}
&ProjectionElem::Subslice { from, to } => match &base.kind(Interner) {
TyKind::Array(inner, c) => {
let next_c = usize_const(
db,
match try_const_usize(db, c) {
None => None,
Some(x) => x.checked_sub(u128::from(from + to)),
},
krate,
);
TyKind::Array(inner.clone(), next_c).intern(Interner)
}
TyKind::Slice(_) => base.clone(),
_ => {
never!("Subslice projection should only happen on slice and array");
TyKind::Error.intern(Interner)
}
},
ProjectionElem::OpaqueCast(_) => {
never!("We don't emit these yet");
TyKind::Error.intern(Interner)
}
}
. It assumes type errors cannot happen, but evidently they can.

@Veykril
Copy link
Member Author

Veykril commented Mar 8, 2024

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
Copy link

adwhit commented Mar 8, 2024

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
Copy link

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
Copy link
Member Author

Veykril commented Mar 13, 2024

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 #15090 (comment) 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
Copy link

Dushistov commented Jul 6, 2024

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 (cae997e 2024-07-03)

bors added a commit that referenced this issue Jul 6, 2024
Also mark InferenceResult::has_errors flag when there are error types

Should work around #15090 (comment)
bors added a commit that referenced this issue Jul 6, 2024
Also mark InferenceResult::has_errors flag when there are error types

Should work around #15090 (comment)
lnicola pushed a commit to lnicola/rust that referenced this issue Jul 11, 2024
Also mark InferenceResult::has_errors flag when there are error types

Should work around rust-lang/rust-analyzer#15090 (comment)
@davidbarsky
Copy link
Contributor

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

@hkaiser25
Copy link

hkaiser25 commented Apr 7, 2025

I see this error too when running a diesel and axum project. Are there any workaround or fixes for this yet? This appears to be crashing rust analyzer a lot for me. It's getting really fustrating for me.

@ChayimFriedman2
Copy link
Contributor

@hkaiser25 This doesn't crash rust-analyzer unless you build from source, and there is a feature flag when building to not crash it.

@hkaiser25
Copy link

@hkaiser25 This doesn't crash rust-analyzer unless you build from source, and there is a feature flag when building to not crash it.

Which feature flag? Will adding this flag to the “cargo check” command that rust analyzer runs in the background fix the crashes for me?

@ChayimFriedman2
Copy link
Contributor

@hkaiser25 No, you need to set the feature flag when building rust-analyzer itself. If you install it from xtask it sets the feature, so you need to edit this line:

"cargo install --path crates/rust-analyzer --profile={profile} --locked --force --features force-always-assert {features...}"

And remove --features force-always-assert.

@hkaiser25
Copy link

hkaiser25 commented Apr 8, 2025

@ChayimFriedman2 Can you advice on whether I should open a new issue to investigate whether this bug might be preventing cargo check from being run. I discovered that whenever I make a change to any diesel code, I will see the error discussed in this issue and this will cause the cargo check to stop working. All errors/warnings I usually see in text editor diasapear and I can't run the cargo check again when I save the file. But other features of rust analyzer work like completions and syntax error detection.

@lnicola
Copy link
Member

lnicola commented Apr 8, 2025

@hkaiser25 you should file a new issue.

@hkaiser25
Copy link

hkaiser25 commented Apr 8, 2025

Just created the issue with a reproducible example. #19543

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-mir C-bug Category: bug
Projects
None yet
Development

No branches or pull requests