about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-12-28 17:00:00 +0000
committerbors <bors@rust-lang.org>2022-12-28 17:00:00 +0000
commit270c94e484e19764a2832ef918c95224eb3f17c7 (patch)
tree8806a01d1ba3dd96bcee4cc7a6eb780b850a12fd /compiler/rustc_hir_analysis
parent83a28ef095ba4179a63196f16eadd97f110d6cb3 (diff)
parentd37cb3ff8935a9d28aa2fdcba2b464bbda96213d (diff)
downloadrust-270c94e484e19764a2832ef918c95224eb3f17c7.tar.gz
rust-270c94e484e19764a2832ef918c95224eb3f17c7.zip
Auto merge of #106215 - matthiaskrgr:rollup-53r89ww, r=matthiaskrgr
Rollup of 6 pull requests

Successful merges:

 - #106028 (docs/test: add UI test and long-form error docs for `E0461`)
 - #106172 (Suggest `impl Iterator` when possible for `_` return type)
 - #106173 (Deduplicate `op` methods)
 - #106176 (Recover `fn` keyword as `Fn` trait in bounds)
 - #106194 (rustdoc: combine common sidebar background color CSS rules)
 - #106199 (Silence knock-down errors on `[type error]` bindings)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_hir_analysis')
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs61
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs13
2 files changed, 67 insertions, 7 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index b7d599f57fd..9e46968c408 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -24,6 +24,8 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericParamKind, Node};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
@@ -31,7 +33,9 @@ use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyC
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::abi;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
+use rustc_trait_selection::traits::ObligationCtxt;
 use std::iter;
 
 mod generics_of;
@@ -1224,7 +1228,17 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                 // to prevent the user from getting a papercut while trying to use the unique closure
                 // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
                 diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
-                diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+                diag.note(
+                    "for more information on `Fn` traits and closure types, see \
+                     https://doc.rust-lang.org/book/ch13-01-closures.html",
+                );
+            } else if let Some(i_ty) = suggest_impl_iterator(tcx, ret_ty, ty.span, hir_id, def_id) {
+                diag.span_suggestion(
+                    ty.span,
+                    "replace with an appropriate return type",
+                    format!("impl Iterator<Item = {}>", i_ty),
+                    Applicability::MachineApplicable,
+                );
             }
             diag.emit();
 
@@ -1242,6 +1256,51 @@ fn infer_return_ty_for_fn_sig<'tcx>(
     }
 }
 
+fn suggest_impl_iterator<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ret_ty: Ty<'tcx>,
+    span: Span,
+    hir_id: hir::HirId,
+    def_id: LocalDefId,
+) -> Option<Ty<'tcx>> {
+    let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) else { return None; };
+    let Some(iterator_item) = tcx.get_diagnostic_item(sym::IteratorItem) else { return None; };
+    if !tcx
+        .infer_ctxt()
+        .build()
+        .type_implements_trait(iter_trait, [ret_ty], tcx.param_env(def_id))
+        .must_apply_modulo_regions()
+    {
+        return None;
+    }
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new_in_snapshot(&infcx);
+    // Find the type of `Iterator::Item`.
+    let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
+    let ty_var = infcx.next_ty_var(origin);
+    let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
+        ty::ProjectionPredicate {
+            projection_ty: tcx.mk_alias_ty(iterator_item, tcx.mk_substs([ret_ty.into()].iter())),
+            term: ty_var.into(),
+        },
+    )));
+    // Add `<ret_ty as Iterator>::Item = _` obligation.
+    ocx.register_obligation(crate::traits::Obligation::misc(
+        tcx,
+        span,
+        hir_id,
+        tcx.param_env(def_id),
+        projection,
+    ));
+    if ocx.select_where_possible().is_empty()
+        && let item_ty = infcx.resolve_vars_if_possible(ty_var)
+        && item_ty.is_suggestable(tcx, false)
+    {
+        return Some(item_ty);
+    }
+    None
+}
+
 fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
     let icx = ItemCtxt::new(tcx, def_id);
     let item = tcx.hir().expect_item(def_id.expect_local());
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index b678990f94e..4bd55a54831 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -5,6 +5,7 @@ use rustc_hir::intravisit;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{HirId, Node};
 use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
@@ -907,10 +908,10 @@ fn infer_placeholder_type<'a>(
                         Applicability::MachineApplicable,
                     );
                 } else {
-                    err.span_note(
+                    with_forced_trimmed_paths!(err.span_note(
                         tcx.hir().body(body_id).value.span,
-                        &format!("however, the inferred type `{}` cannot be named", ty),
-                    );
+                        &format!("however, the inferred type `{ty}` cannot be named"),
+                    ));
                 }
             }
 
@@ -931,10 +932,10 @@ fn infer_placeholder_type<'a>(
                         Applicability::MaybeIncorrect,
                     );
                 } else {
-                    diag.span_note(
+                    with_forced_trimmed_paths!(diag.span_note(
                         tcx.hir().body(body_id).value.span,
-                        &format!("however, the inferred type `{}` cannot be named", ty),
-                    );
+                        &format!("however, the inferred type `{ty}` cannot be named"),
+                    ));
                 }
             }