Skip to content
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

A misdiagnosed case of type mismatch #11847

Open
xffxff opened this issue Mar 30, 2022 · 13 comments
Open

A misdiagnosed case of type mismatch #11847

xffxff opened this issue Mar 30, 2022 · 13 comments
Labels
A-ty type system / type inference / traits / method resolution C-bug Category: bug S-actionable Someone could pick this issue up and work on it right now

Comments

@xffxff
Copy link
Contributor

xffxff commented Mar 30, 2022

rust-analyzer version: bc08b8e 2022-03-28 stable

rustc version: 1.59.0 (9d1b2106e 2022-02-23)

image
I tried the example in https://smallcultfollowing.com/babysteps//blog/2022/03/29/dyn-can-we-make-dyn-sized/ and found that r-a gives wrong diagnostics.

The source code:

use std::fmt::Debug;

fn print_me_later(x: &dyn Debug) -> impl FnOnce() + '_ {
    move || println!("{x:?}")
}

fn main() {
    let f = print_me_later(&22);
    f()
}
@flodiebold flodiebold added A-ty type system / type inference / traits / method resolution S-actionable Someone could pick this issue up and work on it right now C-bug Category: bug labels Mar 30, 2022
@flodiebold
Copy link
Member

flodiebold commented Mar 30, 2022

Interestingly, it works with &22i32, so it seems to be some problem with the handling of integer type variables.

@bitgaoshu
Copy link
Contributor

the literal, like 22, is actually an InferenceVar , except assign a type. In inferring , the InferenceVar with kind Integer can not coercion to Debug, but can coerce to Clone, Sized etc. When infer ended, some inferenceVar will fallback to default. So, hover on 22 is i32. Maybe what we need is to check coerce again after the fallback to eliminate mismatch

@flodiebold
Copy link
Member

Hmm, I don't think that's how rustc handles this. I think rustc doesn't even try to prove that the variable implements Debug while trying to decide whether to coerce, and just records that as an obligation for later. We only coerce if we can prove either uniquely or with definite guidance that the coercion is possible:

Solution::Ambig(Guidance::Definite(subst)) => {
// FIXME need to record an obligation here
canonicalized.apply_solution(self, subst)
}
// FIXME actually we maybe should also accept unknown guidance here
_ => return Err(TypeError),

I think if we accepted any ambiguous result like the FIXME says this might work, though I'm not sure whether it would cause other problems (this requires at least testing on some codebases that it doesn't cause regressions). rustc does this in a more sophisticated way (it has its own trait solving loop specially for coercion), and I'm not sure whether this has any functional differences or is just for better diagnostics.

bitgaoshu added a commit to bitgaoshu/rust-analyzer that referenced this issue May 4, 2022
@bitgaoshu
Copy link
Contributor

I agree. so I found sth like this.

for ty in result.type_of_expr.values_mut() {
*ty = table.resolve_completely(ty.clone());
}
for ty in result.type_of_pat.values_mut() {
*ty = table.resolve_completely(ty.clone());
}
for mismatch in result.type_mismatches.values_mut() {
mismatch.expected = table.resolve_completely(mismatch.expected.clone());
mismatch.actual = table.resolve_completely(mismatch.actual.clone());
}

in line 431, fallback some inferenceVar to i32 so I think in line 437 can check coerce again

@flodiebold
Copy link
Member

flodiebold commented May 4, 2022

I don't think that's a good approach to fix this. The type mismatch is just one symptom of this bug; we need to correctly record the coercion.

@bitgaoshu
Copy link
Contributor

yes.

  1. we have no enough info to decide what the literal type is. the hover i32 is a fallback, a result from L432. In L432, it just covert a InferenceVar, kind = Integer to I32, and no check overflow. so like , Issue hover literal integer fallback overflow i32  #12155. Maybe it's on purpose.
  2. If we change Debug to Clone, of course not runnable, the mismatch info disappeared. Clone is builtin of InferenceVar, kind = Integer. but Debug is not.

截屏2022-05-05 12 03 09

So I think. there are two ways to correctly record the coercion. one is use default i32, the other is InferenceVar, kind = Integer

@flodiebold
Copy link
Member

This problem isn't really related to fallback, it can also happen if we later do find out the concrete type for the literal:

fn main() {
    let i = 22;
    let f = print_me_later(&i);
    let u: u64 = i;
    f()
}

The thing that matters is that it's a variable at the point where we need to coerce, and we can't go back later and change the decision.

@bitgaoshu
Copy link
Contributor

The mismatch's expected is decided. and the actual is not finally decided => When the variable's type is finally decided, the mismatch is finally decided.

@flodiebold
Copy link
Member

As I mentioned before, it's not just about the type mismatch, we need to decide the coercion correctly. Here's a more complicated example where this matters for type inference down the line:

trait Foo<T> { fn get(&self) -> T; }

impl Foo<&'static str> for i32 {
    fn get(&self) -> &'static str {
        "ok"
    }
}

impl Foo<u32> for u32 {
    fn get(&self) -> u32 { *self }
}

fn test() {
    let x = 2;
    let d: &dyn Foo<_> = &x;
    let _: i32 = x;

    eprintln!("{}", d.get().len());
}

@bitgaoshu
Copy link
Contributor

oh. Just for a diagnostic. For this issue, no matter what the literal type is , the diagnostic should not show. So, I think, just check if some literal type matches.

@bitgaoshu
Copy link
Contributor

I also test // FIXME actually we maybe should also accept unknown guidance here . for now, it accept all test

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue May 24, 2023
…h726

Work around `rust-analyzer` false-positive type errors

rust-analyzer incorrectly reports two type errors in `debug.rs`:

> expected &dyn Display, found &i32
> expected &dyn Display, found &i32

This is due to a known bug in r-a: (rust-lang/rust-analyzer#11847).

In these particular cases, changing `&0` to `&0i32` seems to be enough to avoid the bug.
@WaffleLapkin
Copy link
Member

This is marked as S-actionable Someone could pick this issue up and work on it right now , but is it really? Does anyone know how to fix r-a's type inference?

@flodiebold
Copy link
Member

Yes, this is probably blocked on the new trait solver.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ty type system / type inference / traits / method resolution C-bug Category: bug S-actionable Someone could pick this issue up and work on it right now
Projects
None yet
Development

No branches or pull requests

4 participants