about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-04-14 11:36:37 -0400
committerMichael Goulet <michael@errs.io>2024-04-14 11:43:05 -0400
commitb09c17774399bc93ba098cd05cb6c57155f8360b (patch)
tree4db4a2d244c6886698b5c30e4ff3155521b80534
parent78bc0a5656337478cb4163d01ee4429bab5087a9 (diff)
downloadrust-b09c17774399bc93ba098cd05cb6c57155f8360b.tar.gz
rust-b09c17774399bc93ba098cd05cb6c57155f8360b.zip
Don't leak unnameable types in -> _ recover
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs2
-rw-r--r--tests/ui/variance/leaking-unnameables.rs13
-rw-r--r--tests/ui/variance/leaking-unnameables.stderr12
4 files changed, 37 insertions, 17 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index c1bf65367aa..1085caa310b 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1373,16 +1373,16 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             // Don't leak types into signatures unless they're nameable!
             // For example, if a function returns itself, we don't want that
             // recursive function definition to leak out into the fn sig.
-            let mut should_recover = false;
+            let mut recovered_ret_ty = None;
 
-            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
+            if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
-                    ret_ty,
+                    suggestable_ret_ty,
                     Applicability::MachineApplicable,
                 );
-                should_recover = true;
+                recovered_ret_ty = Some(suggestable_ret_ty);
             } else if let Some(sugg) =
                 suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty)
             {
@@ -1404,18 +1404,13 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             }
 
             let guar = diag.emit();
-
-            if should_recover {
-                ty::Binder::dummy(fn_sig)
-            } else {
-                ty::Binder::dummy(tcx.mk_fn_sig(
-                    fn_sig.inputs().iter().copied(),
-                    Ty::new_error(tcx, guar),
-                    fn_sig.c_variadic,
-                    fn_sig.unsafety,
-                    fn_sig.abi,
-                ))
-            }
+            ty::Binder::dummy(tcx.mk_fn_sig(
+                fn_sig.inputs().iter().copied(),
+                recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
+                fn_sig.c_variadic,
+                fn_sig.unsafety,
+                fn_sig.abi,
+            ))
         }
         None => icx.lowerer().lower_fn_ty(
             hir_id,
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 20e4110e137..eeb8b028505 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -236,7 +236,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => {
-                bug!("Unexpected coroutine/closure type in variance computation");
+                bug!("Unexpected unnameable type in variance computation: {ty}");
             }
 
             ty::Ref(region, ty, mutbl) => {
diff --git a/tests/ui/variance/leaking-unnameables.rs b/tests/ui/variance/leaking-unnameables.rs
new file mode 100644
index 00000000000..e51d3779d34
--- /dev/null
+++ b/tests/ui/variance/leaking-unnameables.rs
@@ -0,0 +1,13 @@
+// Test variance computation doesn't explode when we leak unnameable
+// types due to `-> _` recovery.
+
+pub struct Type<'a>(&'a ());
+
+pub fn g() {}
+
+pub fn f<T>() -> _ {
+   //~^ ERROR the placeholder `_` is not allowed within types on item signatures
+   g
+}
+
+fn main() {}
diff --git a/tests/ui/variance/leaking-unnameables.stderr b/tests/ui/variance/leaking-unnameables.stderr
new file mode 100644
index 00000000000..92afe952801
--- /dev/null
+++ b/tests/ui/variance/leaking-unnameables.stderr
@@ -0,0 +1,12 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/leaking-unnameables.rs:8:18
+   |
+LL | pub fn f<T>() -> _ {
+   |                  ^
+   |                  |
+   |                  not allowed in type signatures
+   |                  help: replace with the correct return type: `fn()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0121`.