Skip to content

Commit 300d3fb

Browse files
authored
Rollup merge of #122799 - estebank:issue-122569, r=fee1-dead
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.
2 parents 697b020 + 5fae665 commit 300d3fb

File tree

12 files changed

+119
-54
lines changed

12 files changed

+119
-54
lines changed

compiler/rustc_hir_analysis/src/astconv/bounds.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ fn check_assoc_const_binding_type<'tcx>(
565565
let mut guar = ty.visit_with(&mut collector).break_value();
566566

567567
let ty_note = ty
568-
.make_suggestable(tcx, false)
568+
.make_suggestable(tcx, false, None)
569569
.map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });
570570

571571
let enclosing_item_owner_id = tcx

compiler/rustc_hir_analysis/src/collect.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1371,7 +1371,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
13711371
// recursive function definition to leak out into the fn sig.
13721372
let mut should_recover = false;
13731373

1374-
if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) {
1374+
if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
13751375
diag.span_suggestion(
13761376
ty.span,
13771377
"replace with the correct return type",
@@ -1449,7 +1449,7 @@ fn suggest_impl_trait<'tcx>(
14491449
let ty::Tuple(types) = *args_tuple.kind() else {
14501450
return None;
14511451
};
1452-
let types = types.make_suggestable(tcx, false)?;
1452+
let types = types.make_suggestable(tcx, false, None)?;
14531453
let maybe_ret =
14541454
if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
14551455
Some(format!(
@@ -1507,7 +1507,7 @@ fn suggest_impl_trait<'tcx>(
15071507
// FIXME(compiler-errors): We may benefit from resolving regions here.
15081508
if ocx.select_where_possible().is_empty()
15091509
&& let item_ty = infcx.resolve_vars_if_possible(item_ty)
1510-
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false)
1510+
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false, None)
15111511
&& let Some(sugg) = formatter(
15121512
tcx,
15131513
infcx.resolve_vars_if_possible(args),

compiler/rustc_hir_analysis/src/collect/type_of.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
4747
let ty = tcx.fold_regions(ty, |r, _| {
4848
if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r }
4949
});
50-
let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) {
50+
let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false, None) {
5151
(ty, Some((span, Applicability::MachineApplicable)))
5252
} else {
5353
(ty, None)
@@ -587,7 +587,7 @@ fn infer_placeholder_type<'a>(
587587
suggestions.clear();
588588
}
589589

590-
if let Some(ty) = ty.make_suggestable(tcx, false) {
590+
if let Some(ty) = ty.make_suggestable(tcx, false, None) {
591591
err.span_suggestion(
592592
span,
593593
format!("provide a type for the {kind}"),
@@ -606,7 +606,7 @@ fn infer_placeholder_type<'a>(
606606
let mut diag = bad_placeholder(tcx, vec![span], kind);
607607

608608
if !ty.references_error() {
609-
if let Some(ty) = ty.make_suggestable(tcx, false) {
609+
if let Some(ty) = ty.make_suggestable(tcx, false, None) {
610610
diag.span_suggestion(
611611
span,
612612
"replace with the correct type",

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
809809
return true;
810810
}
811811
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
812-
if let Some(found) = found.make_suggestable(self.tcx, false) {
812+
if let Some(found) = found.make_suggestable(self.tcx, false, None) {
813813
err.subdiagnostic(
814814
self.dcx(),
815815
errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },

compiler/rustc_hir_typeck/src/op.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
601601
if let Some(output_def_id) = output_def_id
602602
&& let Some(trait_def_id) = trait_def_id
603603
&& self.tcx.parent(output_def_id) == trait_def_id
604-
&& let Some(output_ty) =
605-
output_ty.make_suggestable(self.tcx, false)
604+
&& let Some(output_ty) = output_ty
605+
.make_suggestable(self.tcx, false, None)
606606
{
607607
Some(("Output", output_ty))
608608
} else {

compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs

+46-31
Original file line numberDiff line numberDiff line change
@@ -546,40 +546,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
546546
}
547547
}
548548
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
549-
let mut printer = fmt_printer(self, Namespace::ValueNS);
550-
printer.print_def_path(def_id, args).unwrap();
551-
let def_path = printer.into_buffer();
552-
553-
// We only care about whether we have to add `&` or `&mut ` for now.
554-
// This is the case if the last adjustment is a borrow and the
555-
// first adjustment was not a builtin deref.
556-
let adjustment = match typeck_results.expr_adjustments(receiver) {
557-
[
558-
Adjustment { kind: Adjust::Deref(None), target: _ },
559-
..,
560-
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
561-
] => "",
562-
[
563-
..,
564-
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
565-
] => hir::Mutability::from(*mut_).ref_prefix_str(),
566-
_ => "",
567-
};
549+
let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
550+
span: rustc_span::DUMMY_SP,
551+
kind: TypeVariableOriginKind::MiscVariable,
552+
}));
553+
if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) {
554+
let mut printer = fmt_printer(self, Namespace::ValueNS);
555+
printer.print_def_path(def_id, args).unwrap();
556+
let def_path = printer.into_buffer();
557+
558+
// We only care about whether we have to add `&` or `&mut ` for now.
559+
// This is the case if the last adjustment is a borrow and the
560+
// first adjustment was not a builtin deref.
561+
let adjustment = match typeck_results.expr_adjustments(receiver) {
562+
[
563+
Adjustment { kind: Adjust::Deref(None), target: _ },
564+
..,
565+
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
566+
] => "",
567+
[
568+
..,
569+
Adjustment {
570+
kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)),
571+
target: _,
572+
},
573+
] => hir::Mutability::from(*mut_).ref_prefix_str(),
574+
_ => "",
575+
};
568576

569-
multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
570-
receiver.span,
571-
def_path,
572-
adjustment,
573-
successor,
574-
));
577+
multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
578+
receiver.span,
579+
def_path,
580+
adjustment,
581+
successor,
582+
));
583+
}
575584
}
576585
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
577-
let ty_info = ty_to_string(self, ty, None);
578-
multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
579-
ty_info,
580-
data,
581-
should_wrap_expr,
582-
));
586+
let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
587+
span: rustc_span::DUMMY_SP,
588+
kind: TypeVariableOriginKind::MiscVariable,
589+
}));
590+
if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) {
591+
let ty_info = ty_to_string(self, ty, None);
592+
multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
593+
ty_info,
594+
data,
595+
should_wrap_expr,
596+
));
597+
}
583598
}
584599
}
585600
match error_code {

compiler/rustc_middle/src/ty/diagnostics.rs

+22-6
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ pub trait IsSuggestable<'tcx>: Sized {
9191
/// inference variables to be suggestable.
9292
fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
9393

94-
fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>;
94+
fn make_suggestable(
95+
self,
96+
tcx: TyCtxt<'tcx>,
97+
infer_suggestable: bool,
98+
placeholder: Option<Ty<'tcx>>,
99+
) -> Option<Self>;
95100
}
96101

97102
impl<'tcx, T> IsSuggestable<'tcx> for T
@@ -103,8 +108,13 @@ where
103108
self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
104109
}
105110

106-
fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T> {
107-
self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok()
111+
fn make_suggestable(
112+
self,
113+
tcx: TyCtxt<'tcx>,
114+
infer_suggestable: bool,
115+
placeholder: Option<Ty<'tcx>>,
116+
) -> Option<T> {
117+
self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable, placeholder }).ok()
108118
}
109119
}
110120

@@ -559,6 +569,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
559569
pub struct MakeSuggestableFolder<'tcx> {
560570
tcx: TyCtxt<'tcx>,
561571
infer_suggestable: bool,
572+
placeholder: Option<Ty<'tcx>>,
562573
}
563574

564575
impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
@@ -572,19 +583,24 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
572583
let t = match *t.kind() {
573584
Infer(InferTy::TyVar(_)) if self.infer_suggestable => t,
574585

575-
FnDef(def_id, args) => {
586+
FnDef(def_id, args) if self.placeholder.is_none() => {
576587
Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).instantiate(self.tcx, args))
577588
}
578589

579-
// FIXME(compiler-errors): We could replace these with infer, I guess.
580590
Closure(..)
591+
| FnDef(..)
581592
| Infer(..)
582593
| Coroutine(..)
583594
| CoroutineWitness(..)
584595
| Bound(_, _)
585596
| Placeholder(_)
586597
| Error(_) => {
587-
return Err(());
598+
if let Some(placeholder) = self.placeholder {
599+
// We replace these with infer (which is passed in from an infcx).
600+
placeholder
601+
} else {
602+
return Err(());
603+
}
588604
}
589605

590606
Alias(Opaque, AliasTy { def_id, .. }) => {

src/tools/clippy/clippy_lints/src/box_default.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ impl LateLintPass<'_> for BoxDefault {
7070
"try",
7171
if is_plain_default(cx, arg_path) || given_type(cx, expr) {
7272
"Box::default()".into()
73-
} else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) {
73+
} else if let Some(arg_ty) =
74+
cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None)
75+
{
7476
// Check if we can copy from the source expression in the replacement.
7577
// We need the call to have no argument (see `explicit_default_type`).
7678
if inner_call_args.is_empty()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#[derive(Debug)]
2+
enum MyError {
3+
MainError
4+
}
5+
6+
fn main() -> Result<(), MyError> {
7+
let vec = vec!["one", "two", "three"];
8+
let list = vec
9+
.iter()
10+
.map(|s| s.strip_prefix("t"))
11+
.filter_map(Option::Some)
12+
.into()?; //~ ERROR type annotations needed
13+
14+
return Ok(());
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/into-inference-needs-type.rs:12:10
3+
|
4+
LL | .into()?;
5+
| ^^^^
6+
|
7+
= 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}>>`
8+
= 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<_>`
9+
help: try using a fully qualified path to specify the expected types
10+
|
11+
LL ~ let list = <FilterMap<Map<std::slice::Iter<'_, &str>, _>, _> as Into<T>>::into(vec
12+
LL | .iter()
13+
LL | .map(|s| s.strip_prefix("t"))
14+
LL ~ .filter_map(Option::Some))?;
15+
|
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0283`.

tests/ui/traits/suggest-fully-qualified-closure.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//@ check-fail
22
//@ known-bug: #103705
3-
//@ normalize-stderr-test "\{closure@.*\}" -> "{closure@}"
4-
//@ normalize-stderr-test "\+* ~" -> "+++ ~"
53

64
// The output of this currently suggests writing a closure in the qualified path.
75

tests/ui/traits/suggest-fully-qualified-closure.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0283]: type annotations needed
2-
--> $DIR/suggest-fully-qualified-closure.rs:23:7
2+
--> $DIR/suggest-fully-qualified-closure.rs:21:7
33
|
44
LL | q.lol(||());
55
| ^^^
66
|
77
note: multiple `impl`s satisfying `Qqq: MyTrait<_>` found
8-
--> $DIR/suggest-fully-qualified-closure.rs:14:1
8+
--> $DIR/suggest-fully-qualified-closure.rs:12:1
99
|
1010
LL | impl MyTrait<u32> for Qqq{
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,8 +14,8 @@ LL | impl MyTrait<u64> for Qqq{
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^
1515
help: try using a fully qualified path to specify the expected types
1616
|
17-
LL | <Qqq as MyTrait<T>>::lol::<{closure@}>(&q, ||());
18-
| +++ ~
17+
LL | <Qqq as MyTrait<T>>::lol::<_>(&q, ||());
18+
| +++++++++++++++++++++++++++++++ ~
1919

2020
error: aborting due to 1 previous error
2121

0 commit comments

Comments
 (0)