about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-12-13 15:10:58 +0000
committerMichael Goulet <michael@errs.io>2024-12-13 15:11:04 +0000
commitd82c520f1435e0fe646f749f9e71ceee825180ed (patch)
tree30be96dc965d842a5f3931adbf980fb8cab7cb6e /compiler/rustc_hir_analysis/src
parent4847d6a9d07d4be9ba3196f6ad444af2d7bdde72 (diff)
downloadrust-d82c520f1435e0fe646f749f9e71ceee825180ed.tar.gz
rust-d82c520f1435e0fe646f749f9e71ceee825180ed.zip
Clean up infer_return_ty_for_fn_sig
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs179
1 files changed, 94 insertions, 85 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 96d2714252a..1f322b26af3 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1330,7 +1330,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
             ..
         })
         | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
-            infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
+            lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
         }
 
         ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
@@ -1347,7 +1347,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
                     None,
                 )
             } else {
-                infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
+                lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
             }
         }
 
@@ -1397,99 +1397,108 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
     ty::EarlyBinder::bind(output)
 }
 
-fn infer_return_ty_for_fn_sig<'tcx>(
-    sig: &hir::FnSig<'tcx>,
-    generics: &hir::Generics<'_>,
+fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
+    icx: &ItemCtxt<'tcx>,
+    sig: &'tcx hir::FnSig<'tcx>,
+    generics: &'tcx hir::Generics<'tcx>,
     def_id: LocalDefId,
+) -> ty::PolyFnSig<'tcx> {
+    if let Some(infer_ret_ty) = sig.decl.output.get_infer_ret_ty() {
+        return recover_infer_ret_ty(icx, infer_ret_ty, generics, def_id);
+    }
+
+    icx.lowerer().lower_fn_ty(
+        icx.tcx().local_def_id_to_hir_id(def_id),
+        sig.header.safety,
+        sig.header.abi,
+        sig.decl,
+        Some(generics),
+        None,
+    )
+}
+
+fn recover_infer_ret_ty<'tcx>(
     icx: &ItemCtxt<'tcx>,
+    infer_ret_ty: &'tcx hir::Ty<'tcx>,
+    generics: &'tcx hir::Generics<'tcx>,
+    def_id: LocalDefId,
 ) -> ty::PolyFnSig<'tcx> {
     let tcx = icx.tcx;
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
-    match sig.decl.output.get_infer_ret_ty() {
-        Some(ty) => {
-            let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
-            // Typeck doesn't expect erased regions to be returned from `type_of`.
-            // This is a heuristic approach. If the scope has region parameters,
-            // we should change fn_sig's lifetime from `ReErased` to `ReError`,
-            // otherwise to `ReStatic`.
-            let has_region_params = generics.params.iter().any(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => true,
-                _ => false,
-            });
-            let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
-                ty::ReErased => {
-                    if has_region_params {
-                        ty::Region::new_error_with_message(
-                            tcx,
-                            DUMMY_SP,
-                            "erased region is not allowed here in return type",
-                        )
-                    } else {
-                        tcx.lifetimes.re_static
-                    }
-                }
-                _ => r,
-            });
+    let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
 
-            let mut visitor = HirPlaceholderCollector::default();
-            visitor.visit_ty(ty);
-
-            let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
-            let ret_ty = fn_sig.output();
-            // 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 recovered_ret_ty = 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",
-                    suggestable_ret_ty,
-                    Applicability::MachineApplicable,
-                );
-                recovered_ret_ty = Some(suggestable_ret_ty);
-            } else if let Some(sugg) = suggest_impl_trait(
-                &tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
-                tcx.param_env(def_id),
-                ret_ty,
-            ) {
-                diag.span_suggestion(
-                    ty.span,
-                    "replace with an appropriate return type",
-                    sugg,
-                    Applicability::MachineApplicable,
-                );
-            } else if ret_ty.is_closure() {
-                diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
-            }
-            // Also note how `Fn` traits work just in case!
-            if ret_ty.is_closure() {
-                diag.note(
-                    "for more information on `Fn` traits and closure types, see \
-                     https://doc.rust-lang.org/book/ch13-01-closures.html",
-                );
+    // Typeck doesn't expect erased regions to be returned from `type_of`.
+    // This is a heuristic approach. If the scope has region parameters,
+    // we should change fn_sig's lifetime from `ReErased` to `ReError`,
+    // otherwise to `ReStatic`.
+    let has_region_params = generics.params.iter().any(|param| match param.kind {
+        GenericParamKind::Lifetime { .. } => true,
+        _ => false,
+    });
+    let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
+        ty::ReErased => {
+            if has_region_params {
+                ty::Region::new_error_with_message(
+                    tcx,
+                    DUMMY_SP,
+                    "erased region is not allowed here in return type",
+                )
+            } else {
+                tcx.lifetimes.re_static
             }
-
-            let guar = diag.emit();
-            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.safety,
-                fn_sig.abi,
-            ))
         }
-        None => icx.lowerer().lower_fn_ty(
-            hir_id,
-            sig.header.safety,
-            sig.header.abi,
-            sig.decl,
-            Some(generics),
-            None,
-        ),
+        _ => r,
+    });
+
+    let mut visitor = HirPlaceholderCollector::default();
+    visitor.visit_ty(infer_ret_ty);
+
+    let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
+    let ret_ty = fn_sig.output();
+
+    // 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 recovered_ret_ty = None;
+    if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
+        diag.span_suggestion(
+            infer_ret_ty.span,
+            "replace with the correct return type",
+            suggestable_ret_ty,
+            Applicability::MachineApplicable,
+        );
+        recovered_ret_ty = Some(suggestable_ret_ty);
+    } else if let Some(sugg) = suggest_impl_trait(
+        &tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
+        tcx.param_env(def_id),
+        ret_ty,
+    ) {
+        diag.span_suggestion(
+            infer_ret_ty.span,
+            "replace with an appropriate return type",
+            sugg,
+            Applicability::MachineApplicable,
+        );
+    } else if ret_ty.is_closure() {
+        diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
+    }
+
+    // Also note how `Fn` traits work just in case!
+    if ret_ty.is_closure() {
+        diag.note(
+            "for more information on `Fn` traits and closure types, see \
+                     https://doc.rust-lang.org/book/ch13-01-closures.html",
+        );
     }
+    let guar = diag.emit();
+    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.safety,
+        fn_sig.abi,
+    ))
 }
 
 pub fn suggest_impl_trait<'tcx>(