about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-10-03 08:58:48 +0200
committerGitHub <noreply@github.com>2023-10-03 08:58:48 +0200
commit634e5c9ba2ddc155ae95b91d21f511a8a22e9206 (patch)
tree98e4bc3a513f35863df6704a09df7b5c5f68e486
parentff3b15e2bf19d39b2c8463afda183c387d993569 (diff)
parentac5aa8c1a4370b34674d18ef20b642645d2172e0 (diff)
downloadrust-634e5c9ba2ddc155ae95b91d21f511a8a22e9206.tar.gz
rust-634e5c9ba2ddc155ae95b91d21f511a8a22e9206.zip
Rollup merge of #116158 - compiler-errors:unconstrained-type-var-sugg, r=wesleywiser
Don't suggest nonsense suggestions for unconstrained type vars in `note_source_of_type_mismatch_constraint`

The way we do type inference for suggestions in `note_source_of_type_mismatch_constraint` is a bit strange. We compute the "ideal" method signature, which takes the receiver that we *want* and uses it to compute the types of the arguments that would have given us that receiver via type inference, and use *that* to suggest how to change an argument to make sure our receiver type is inferred correctly.

The problem is that sometimes we have totally unconstrained arguments (well, they're constrained by things outside of the type checker per se, like associated types), and therefore type suggestions are happy to coerce anything to that unconstrained argument. This leads to bogus suggestions, like #116155. This is partly due to above, and partly due to the fact that `emit_type_mismatch_suggestions` doesn't double check that its suggestions are actually compatible with the program other than trying to satisfy the type mismatch.

This adds a hack to make sure that at least the types are fully constrained, but I guess I could also rip out this logic altogether. There would be some sad diagnostics regressions though, such as `tests/ui/type/type-check/point-at-inference-4.rs`.

Fixes #116155
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs10
-rw-r--r--tests/ui/type/type-check/point-at-inference-issue-116155.rs17
-rw-r--r--tests/ui/type/type-check/point-at-inference-issue-116155.stderr18
3 files changed, 43 insertions, 2 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index d97691369c9..5c3f2b85966 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable};
+use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt as _;
@@ -504,12 +504,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // incompatible fix at the original mismatch site.
                     if matches!(source, TypeMismatchSource::Ty(_))
                         && let Some(ideal_method) = ideal_method
+                        && let ideal_arg_ty = self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1])
+                        // HACK(compiler-errors): We don't actually consider the implications
+                        // of our inference guesses in `emit_type_mismatch_suggestions`, so
+                        // only suggest things when we know our type error is precisely due to
+                        // a type mismatch, and not via some projection or something. See #116155.
+                        && !ideal_arg_ty.has_non_region_infer()
                     {
                         self.emit_type_mismatch_suggestions(
                             err,
                             arg_expr,
                             arg_ty,
-                            self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1]),
+                            ideal_arg_ty,
                             None,
                             None,
                         );
diff --git a/tests/ui/type/type-check/point-at-inference-issue-116155.rs b/tests/ui/type/type-check/point-at-inference-issue-116155.rs
new file mode 100644
index 00000000000..1e9942d42e8
--- /dev/null
+++ b/tests/ui/type/type-check/point-at-inference-issue-116155.rs
@@ -0,0 +1,17 @@
+struct S<T>(T);
+
+impl<T> S<T> {
+    fn new() -> Self {
+        loop {}
+    }
+
+    fn constrain<F: Fn() -> T>(&self, _f: F) {}
+}
+
+fn main() {
+    let s = S::new();
+    let c = || true;
+    s.constrain(c);
+    let _: S<usize> = s;
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/type/type-check/point-at-inference-issue-116155.stderr b/tests/ui/type/type-check/point-at-inference-issue-116155.stderr
new file mode 100644
index 00000000000..c8c01603cb8
--- /dev/null
+++ b/tests/ui/type/type-check/point-at-inference-issue-116155.stderr
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/point-at-inference-issue-116155.rs:15:23
+   |
+LL |     s.constrain(c);
+   |     -           - this argument has type `{closure@$DIR/point-at-inference-issue-116155.rs:13:13: 13:15}`...
+   |     |
+   |     ... which causes `s` to have type `S<bool>`
+LL |     let _: S<usize> = s;
+   |            --------   ^ expected `S<usize>`, found `S<bool>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `S<usize>`
+              found struct `S<bool>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.