Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace closures with _ when suggesting fully qualified path for method call #122799

Merged
merged 1 commit into from Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/astconv/bounds.rs
Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these parameters are quite hard to read now. it might make sense to pass in a struct that configures it instead of these opaque params (though I guess the IDE will display the parameter name so it is more readable)

.map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });

let enclosing_item_owner_id = tcx
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/collect.rs
Expand Up @@ -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",
Expand Down Expand Up @@ -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!(
Expand Down Expand Up @@ -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),
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Expand Up @@ -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)
Expand Down Expand Up @@ -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}"),
Expand All @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Expand Up @@ -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() },
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/op.rs
Expand Up @@ -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 {
Expand Down
77 changes: 46 additions & 31 deletions compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
Expand Up @@ -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 {
Expand Down
28 changes: 22 additions & 6 deletions compiler/rustc_middle/src/ty/diagnostics.rs
Expand Up @@ -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
Expand All @@ -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()
}
}

Expand Down Expand Up @@ -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> {
Expand All @@ -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, .. }) => {
Expand Down
4 changes: 3 additions & 1 deletion src/tools/clippy/clippy_lints/src/box_default.rs
Expand Up @@ -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()
Expand Down
15 changes: 15 additions & 0 deletions 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(());
}
19 changes: 19 additions & 0 deletions 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`.
2 changes: 0 additions & 2 deletions 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.

Expand Down
8 changes: 4 additions & 4 deletions 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{
| ^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -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

Expand Down