about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-03-20 22:50:32 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-03-21 00:07:44 +0000
commit5fae66592494d37aa9b7c3add8c0e6077e0833f7 (patch)
tree2adac5cac5f329524fffd63c416e5a81346d1c17
parenta128516cf9de352ae1f9d430ed730363c7ca3c0c (diff)
downloadrust-5fae66592494d37aa9b7c3add8c0e6077e0833f7.tar.gz
rust-5fae66592494d37aa9b7c3add8c0e6077e0833f7.zip
Replace closures with `_` when suggesting fully qualified path for method call
```
error[E0283]: type annotations needed
  --> $DIR/into-inference-needs-type.rs:12:10
   |
LL |         .into()?;
   |          ^^^^
   |
   = note: cannot satisfy `_: From<...>`
   = note: required for `FilterMap<...>` to implement `Into<_>`
help: try using a fully qualified path to specify the expected types
   |
LL ~     let list = <FilterMap<Map<std::slice::Iter<'_, &str>, _>, _> as Into<T>>::into(vec
LL |         .iter()
LL |         .map(|s| s.strip_prefix("t"))
LL ~         .filter_map(Option::Some))?;
   |
```

Fix #122569.
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs77
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs4
-rw-r--r--tests/ui/suggestions/types/into-inference-needs-type.rs15
-rw-r--r--tests/ui/suggestions/types/into-inference-needs-type.stderr19
-rw-r--r--tests/ui/traits/suggest-fully-qualified-closure.rs2
-rw-r--r--tests/ui/traits/suggest-fully-qualified-closure.stderr8
12 files changed, 119 insertions, 54 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 3067e2d0b71..7a5cb6e9d6f 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -565,7 +565,7 @@ fn check_assoc_const_binding_type<'tcx>(
     let mut guar = ty.visit_with(&mut collector).break_value();
 
     let ty_note = ty
-        .make_suggestable(tcx, false)
+        .make_suggestable(tcx, false, None)
         .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });
 
     let enclosing_item_owner_id = tcx
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 5cd6862786b..d8bcc3a687e 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1364,7 +1364,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             // recursive function definition to leak out into the fn sig.
             let mut should_recover = false;
 
-            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) {
+            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
@@ -1442,7 +1442,7 @@ fn suggest_impl_trait<'tcx>(
             let ty::Tuple(types) = *args_tuple.kind() else {
                 return None;
             };
-            let types = types.make_suggestable(tcx, false)?;
+            let types = types.make_suggestable(tcx, false, None)?;
             let maybe_ret =
                 if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
             Some(format!(
@@ -1500,7 +1500,7 @@ fn suggest_impl_trait<'tcx>(
         // FIXME(compiler-errors): We may benefit from resolving regions here.
         if ocx.select_where_possible().is_empty()
             && let item_ty = infcx.resolve_vars_if_possible(item_ty)
-            && let Some(item_ty) = item_ty.make_suggestable(tcx, false)
+            && let Some(item_ty) = item_ty.make_suggestable(tcx, false, None)
             && let Some(sugg) = formatter(
                 tcx,
                 infcx.resolve_vars_if_possible(args),
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index fd86f2dd1b1..cec01abae4b 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -47,7 +47,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             let ty = tcx.fold_regions(ty, |r, _| {
                 if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r }
             });
-            let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) {
+            let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                 (ty, Some((span, Applicability::MachineApplicable)))
             } else {
                 (ty, None)
@@ -587,7 +587,7 @@ fn infer_placeholder_type<'a>(
                     suggestions.clear();
                 }
 
-                if let Some(ty) = ty.make_suggestable(tcx, false) {
+                if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                     err.span_suggestion(
                         span,
                         format!("provide a type for the {kind}"),
@@ -606,7 +606,7 @@ fn infer_placeholder_type<'a>(
             let mut diag = bad_placeholder(tcx, vec![span], kind);
 
             if !ty.references_error() {
-                if let Some(ty) = ty.make_suggestable(tcx, false) {
+                if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                     diag.span_suggestion(
                         span,
                         "replace with the correct type",
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 3f6f4cccba7..f4090feee17 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -809,7 +809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return true;
             }
             &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
-                if let Some(found) = found.make_suggestable(self.tcx, false) {
+                if let Some(found) = found.make_suggestable(self.tcx, false, None) {
                     err.subdiagnostic(
                         self.dcx(),
                         errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 79f574aa7fd..8969030d683 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -601,8 +601,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                             if let Some(output_def_id) = output_def_id
                                                 && let Some(trait_def_id) = trait_def_id
                                                 && self.tcx.parent(output_def_id) == trait_def_id
-                                                && let Some(output_ty) =
-                                                    output_ty.make_suggestable(self.tcx, false)
+                                                && let Some(output_ty) = output_ty
+                                                    .make_suggestable(self.tcx, false, None)
                                             {
                                                 Some(("Output", output_ty))
                                             } else {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 0686994b037..ce9001ccb1c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -546,40 +546,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
             }
             InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
-                let mut printer = fmt_printer(self, Namespace::ValueNS);
-                printer.print_def_path(def_id, args).unwrap();
-                let def_path = printer.into_buffer();
-
-                // We only care about whether we have to add `&` or `&mut ` for now.
-                // This is the case if the last adjustment is a borrow and the
-                // first adjustment was not a builtin deref.
-                let adjustment = match typeck_results.expr_adjustments(receiver) {
-                    [
-                        Adjustment { kind: Adjust::Deref(None), target: _ },
-                        ..,
-                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
-                    ] => "",
-                    [
-                        ..,
-                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
-                    ] => hir::Mutability::from(*mut_).ref_prefix_str(),
-                    _ => "",
-                };
+                let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
+                    span: rustc_span::DUMMY_SP,
+                    kind: TypeVariableOriginKind::MiscVariable,
+                }));
+                if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) {
+                    let mut printer = fmt_printer(self, Namespace::ValueNS);
+                    printer.print_def_path(def_id, args).unwrap();
+                    let def_path = printer.into_buffer();
+
+                    // We only care about whether we have to add `&` or `&mut ` for now.
+                    // This is the case if the last adjustment is a borrow and the
+                    // first adjustment was not a builtin deref.
+                    let adjustment = match typeck_results.expr_adjustments(receiver) {
+                        [
+                            Adjustment { kind: Adjust::Deref(None), target: _ },
+                            ..,
+                            Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
+                        ] => "",
+                        [
+                            ..,
+                            Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)),
+                                target: _,
+                            },
+                        ] => hir::Mutability::from(*mut_).ref_prefix_str(),
+                        _ => "",
+                    };
 
-                multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
-                    receiver.span,
-                    def_path,
-                    adjustment,
-                    successor,
-                ));
+                    multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
+                        receiver.span,
+                        def_path,
+                        adjustment,
+                        successor,
+                    ));
+                }
             }
             InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
-                let ty_info = ty_to_string(self, ty, None);
-                multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
-                    ty_info,
-                    data,
-                    should_wrap_expr,
-                ));
+                let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
+                    span: rustc_span::DUMMY_SP,
+                    kind: TypeVariableOriginKind::MiscVariable,
+                }));
+                if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) {
+                    let ty_info = ty_to_string(self, ty, None);
+                    multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
+                        ty_info,
+                        data,
+                        should_wrap_expr,
+                    ));
+                }
             }
         }
         match error_code {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 05463b8554f..ee18647cdd8 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -91,7 +91,12 @@ pub trait IsSuggestable<'tcx>: Sized {
     /// inference variables to be suggestable.
     fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
 
-    fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>;
+    fn make_suggestable(
+        self,
+        tcx: TyCtxt<'tcx>,
+        infer_suggestable: bool,
+        placeholder: Option<Ty<'tcx>>,
+    ) -> Option<Self>;
 }
 
 impl<'tcx, T> IsSuggestable<'tcx> for T
@@ -103,8 +108,13 @@ where
         self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
     }
 
-    fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T> {
-        self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok()
+    fn make_suggestable(
+        self,
+        tcx: TyCtxt<'tcx>,
+        infer_suggestable: bool,
+        placeholder: Option<Ty<'tcx>>,
+    ) -> Option<T> {
+        self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable, placeholder }).ok()
     }
 }
 
@@ -559,6 +569,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
 pub struct MakeSuggestableFolder<'tcx> {
     tcx: TyCtxt<'tcx>,
     infer_suggestable: bool,
+    placeholder: Option<Ty<'tcx>>,
 }
 
 impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
@@ -572,19 +583,24 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
         let t = match *t.kind() {
             Infer(InferTy::TyVar(_)) if self.infer_suggestable => t,
 
-            FnDef(def_id, args) => {
+            FnDef(def_id, args) if self.placeholder.is_none() => {
                 Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).instantiate(self.tcx, args))
             }
 
-            // FIXME(compiler-errors): We could replace these with infer, I guess.
             Closure(..)
+            | FnDef(..)
             | Infer(..)
             | Coroutine(..)
             | CoroutineWitness(..)
             | Bound(_, _)
             | Placeholder(_)
             | Error(_) => {
-                return Err(());
+                if let Some(placeholder) = self.placeholder {
+                    // We replace these with infer (which is passed in from an infcx).
+                    placeholder
+                } else {
+                    return Err(());
+                }
             }
 
             Alias(Opaque, AliasTy { def_id, .. }) => {
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 779ae03c464..66206d1a059 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -70,7 +70,9 @@ impl LateLintPass<'_> for BoxDefault {
                 "try",
                 if is_plain_default(cx, arg_path) || given_type(cx, expr) {
                     "Box::default()".into()
-                } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) {
+                } else if let Some(arg_ty) =
+                    cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None)
+                {
                     // Check if we can copy from the source expression in the replacement.
                     // We need the call to have no argument (see `explicit_default_type`).
                     if inner_call_args.is_empty()
diff --git a/tests/ui/suggestions/types/into-inference-needs-type.rs b/tests/ui/suggestions/types/into-inference-needs-type.rs
new file mode 100644
index 00000000000..4c8b6ec2113
--- /dev/null
+++ b/tests/ui/suggestions/types/into-inference-needs-type.rs
@@ -0,0 +1,15 @@
+#[derive(Debug)]
+enum MyError {
+    MainError
+}
+
+fn main() -> Result<(), MyError> {
+    let vec = vec!["one", "two", "three"];
+    let list = vec
+        .iter()
+        .map(|s| s.strip_prefix("t"))
+        .filter_map(Option::Some)
+        .into()?; //~ ERROR type annotations needed
+
+    return Ok(());
+}
diff --git a/tests/ui/suggestions/types/into-inference-needs-type.stderr b/tests/ui/suggestions/types/into-inference-needs-type.stderr
new file mode 100644
index 00000000000..dd688f90289
--- /dev/null
+++ b/tests/ui/suggestions/types/into-inference-needs-type.stderr
@@ -0,0 +1,19 @@
+error[E0283]: type annotations needed
+  --> $DIR/into-inference-needs-type.rs:12:10
+   |
+LL |         .into()?;
+   |          ^^^^
+   |
+   = note: cannot satisfy `_: From<FilterMap<Map<std::slice::Iter<'_, &str>, {closure@$DIR/into-inference-needs-type.rs:10:14: 10:17}>, fn(Option<&str>) -> Option<Option<&str>> {Option::<Option<&str>>::Some}>>`
+   = note: required for `FilterMap<Map<std::slice::Iter<'_, &str>, {closure@$DIR/into-inference-needs-type.rs:10:14: 10:17}>, fn(Option<&str>) -> Option<Option<&str>> {Option::<Option<&str>>::Some}>` to implement `Into<_>`
+help: try using a fully qualified path to specify the expected types
+   |
+LL ~     let list = <FilterMap<Map<std::slice::Iter<'_, &str>, _>, _> as Into<T>>::into(vec
+LL |         .iter()
+LL |         .map(|s| s.strip_prefix("t"))
+LL ~         .filter_map(Option::Some))?;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/suggest-fully-qualified-closure.rs b/tests/ui/traits/suggest-fully-qualified-closure.rs
index f401a3012da..3d28a4e6bf5 100644
--- a/tests/ui/traits/suggest-fully-qualified-closure.rs
+++ b/tests/ui/traits/suggest-fully-qualified-closure.rs
@@ -1,7 +1,5 @@
 //@ check-fail
 //@ known-bug: #103705
-//@ normalize-stderr-test "\{closure@.*\}" -> "{closure@}"
-//@ normalize-stderr-test "\+* ~" -> "+++ ~"
 
 // The output of this currently suggests writing a closure in the qualified path.
 
diff --git a/tests/ui/traits/suggest-fully-qualified-closure.stderr b/tests/ui/traits/suggest-fully-qualified-closure.stderr
index e077bd7ac2a..a2c1115e673 100644
--- a/tests/ui/traits/suggest-fully-qualified-closure.stderr
+++ b/tests/ui/traits/suggest-fully-qualified-closure.stderr
@@ -1,11 +1,11 @@
 error[E0283]: type annotations needed
-  --> $DIR/suggest-fully-qualified-closure.rs:23:7
+  --> $DIR/suggest-fully-qualified-closure.rs:21:7
    |
 LL |     q.lol(||());
    |       ^^^
    |
 note: multiple `impl`s satisfying `Qqq: MyTrait<_>` found
-  --> $DIR/suggest-fully-qualified-closure.rs:14:1
+  --> $DIR/suggest-fully-qualified-closure.rs:12:1
    |
 LL | impl MyTrait<u32> for Qqq{
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,8 +14,8 @@ LL | impl MyTrait<u64> for Qqq{
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 help: try using a fully qualified path to specify the expected types
    |
-LL |     <Qqq as MyTrait<T>>::lol::<{closure@}>(&q, ||());
-   |     +++ ~
+LL |     <Qqq as MyTrait<T>>::lol::<_>(&q, ||());
+   |     +++++++++++++++++++++++++++++++ ~
 
 error: aborting due to 1 previous error