Rollup merge of #123761 - compiler-errors:suggest-more-impl-trait, r=estebank
Use `suggest_impl_trait` in return type suggestion on type error Discovered while doing other refactoring. Review with whitespace disabled. r? estebank
This commit is contained in:
commit
2930dce479
@ -30,7 +30,7 @@
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
@ -1383,7 +1383,9 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
should_recover = true;
|
||||
} else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) {
|
||||
} else if let Some(sugg) =
|
||||
suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty)
|
||||
{
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"replace with an appropriate return type",
|
||||
@ -1426,11 +1428,10 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_impl_trait<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pub fn suggest_impl_trait<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ret_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
def_id: LocalDefId,
|
||||
) -> Option<String> {
|
||||
let format_as_assoc: fn(_, _, _, _, _) -> _ =
|
||||
|tcx: TyCtxt<'tcx>,
|
||||
@ -1464,24 +1465,28 @@ fn suggest_impl_trait<'tcx>(
|
||||
|
||||
for (trait_def_id, assoc_item_def_id, formatter) in [
|
||||
(
|
||||
tcx.get_diagnostic_item(sym::Iterator),
|
||||
tcx.get_diagnostic_item(sym::IteratorItem),
|
||||
infcx.tcx.get_diagnostic_item(sym::Iterator),
|
||||
infcx.tcx.get_diagnostic_item(sym::IteratorItem),
|
||||
format_as_assoc,
|
||||
),
|
||||
(
|
||||
tcx.lang_items().future_trait(),
|
||||
tcx.get_diagnostic_item(sym::FutureOutput),
|
||||
infcx.tcx.lang_items().future_trait(),
|
||||
infcx.tcx.get_diagnostic_item(sym::FutureOutput),
|
||||
format_as_assoc,
|
||||
),
|
||||
(tcx.lang_items().fn_trait(), tcx.lang_items().fn_once_output(), format_as_parenthesized),
|
||||
(
|
||||
tcx.lang_items().fn_mut_trait(),
|
||||
tcx.lang_items().fn_once_output(),
|
||||
infcx.tcx.lang_items().fn_trait(),
|
||||
infcx.tcx.lang_items().fn_once_output(),
|
||||
format_as_parenthesized,
|
||||
),
|
||||
(
|
||||
tcx.lang_items().fn_once_trait(),
|
||||
tcx.lang_items().fn_once_output(),
|
||||
infcx.tcx.lang_items().fn_mut_trait(),
|
||||
infcx.tcx.lang_items().fn_once_output(),
|
||||
format_as_parenthesized,
|
||||
),
|
||||
(
|
||||
infcx.tcx.lang_items().fn_once_trait(),
|
||||
infcx.tcx.lang_items().fn_once_output(),
|
||||
format_as_parenthesized,
|
||||
),
|
||||
] {
|
||||
@ -1491,36 +1496,45 @@ fn suggest_impl_trait<'tcx>(
|
||||
let Some(assoc_item_def_id) = assoc_item_def_id else {
|
||||
continue;
|
||||
};
|
||||
if tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy {
|
||||
if infcx.tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy {
|
||||
continue;
|
||||
}
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let args = ty::GenericArgs::for_item(tcx, trait_def_id, |param, _| {
|
||||
if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(span, param) }
|
||||
let sugg = infcx.probe(|_| {
|
||||
let args = ty::GenericArgs::for_item(infcx.tcx, trait_def_id, |param, _| {
|
||||
if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(DUMMY_SP, param) }
|
||||
});
|
||||
if !infcx
|
||||
.type_implements_trait(trait_def_id, args, param_env)
|
||||
.must_apply_modulo_regions()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let item_ty = ocx.normalize(
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
Ty::new_projection(infcx.tcx, assoc_item_def_id, args),
|
||||
);
|
||||
// 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(infcx.tcx, false, None)
|
||||
&& let Some(sugg) = formatter(
|
||||
infcx.tcx,
|
||||
infcx.resolve_vars_if_possible(args),
|
||||
trait_def_id,
|
||||
assoc_item_def_id,
|
||||
item_ty,
|
||||
)
|
||||
{
|
||||
return Some(sugg);
|
||||
}
|
||||
|
||||
None
|
||||
});
|
||||
if !infcx.type_implements_trait(trait_def_id, args, param_env).must_apply_modulo_regions() {
|
||||
continue;
|
||||
}
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let item_ty = ocx.normalize(
|
||||
&ObligationCause::misc(span, def_id),
|
||||
param_env,
|
||||
Ty::new_projection(tcx, assoc_item_def_id, args),
|
||||
);
|
||||
// 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, None)
|
||||
&& let Some(sugg) = formatter(
|
||||
tcx,
|
||||
infcx.resolve_vars_if_possible(args),
|
||||
trait_def_id,
|
||||
assoc_item_def_id,
|
||||
item_ty,
|
||||
)
|
||||
{
|
||||
return Some(sugg);
|
||||
|
||||
if sugg.is_some() {
|
||||
return sugg;
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -20,6 +20,7 @@
|
||||
CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node,
|
||||
Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||
};
|
||||
use rustc_hir_analysis::collect::suggest_impl_trait;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_infer::traits::{self};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
@ -814,17 +815,10 @@ pub(in super::super) fn suggest_missing_return_type(
|
||||
errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },
|
||||
);
|
||||
return true;
|
||||
} else if let ty::Closure(_, args) = found.kind()
|
||||
// FIXME(compiler-errors): Get better at printing binders...
|
||||
&& let closure = args.as_closure()
|
||||
&& closure.sig().is_suggestable(self.tcx, false)
|
||||
{
|
||||
} else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::AddReturnTypeSuggestion::Add {
|
||||
span,
|
||||
found: closure.print_as_impl_trait().to_string(),
|
||||
},
|
||||
errors::AddReturnTypeSuggestion::Add { span, found: sugg },
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
|
@ -62,7 +62,7 @@ error[E0308]: mismatched types
|
||||
--> $DIR/async-closure-gate.rs:27:5
|
||||
|
|
||||
LL | fn foo3() {
|
||||
| - help: a return type might be missing here: `-> _`
|
||||
| - help: try adding a return type: `-> impl Future<Output = ()>`
|
||||
LL | / async {
|
||||
LL | |
|
||||
LL | | let _ = #[track_caller] || {
|
||||
@ -78,7 +78,7 @@ error[E0308]: mismatched types
|
||||
--> $DIR/async-closure-gate.rs:44:5
|
||||
|
|
||||
LL | fn foo5() {
|
||||
| - help: a return type might be missing here: `-> _`
|
||||
| - help: try adding a return type: `-> impl Future<Output = ()>`
|
||||
LL | / async {
|
||||
LL | |
|
||||
LL | | let _ = || {
|
||||
|
@ -62,7 +62,7 @@ error[E0308]: mismatched types
|
||||
--> $DIR/async-closure-gate.rs:27:5
|
||||
|
|
||||
LL | fn foo3() {
|
||||
| - help: a return type might be missing here: `-> _`
|
||||
| - help: try adding a return type: `-> impl Future<Output = ()>`
|
||||
LL | / async {
|
||||
LL | |
|
||||
LL | | let _ = #[track_caller] || {
|
||||
@ -78,7 +78,7 @@ error[E0308]: mismatched types
|
||||
--> $DIR/async-closure-gate.rs:44:5
|
||||
|
|
||||
LL | fn foo5() {
|
||||
| - help: a return type might be missing here: `-> _`
|
||||
| - help: try adding a return type: `-> impl Future<Output = ()>`
|
||||
LL | / async {
|
||||
LL | |
|
||||
LL | | let _ = || {
|
||||
|
@ -2,7 +2,7 @@ error[E0308]: mismatched types
|
||||
--> $DIR/return-closures.rs:3:5
|
||||
|
|
||||
LL | fn foo() {
|
||||
| - help: try adding a return type: `-> impl for<'a> Fn(&'a i32) -> i32`
|
||||
| - help: try adding a return type: `-> impl FnOnce(&i32) -> i32`
|
||||
LL |
|
||||
LL | |x: &i32| 1i32
|
||||
| ^^^^^^^^^^^^^^ expected `()`, found closure
|
||||
|
@ -1,5 +1,5 @@
|
||||
#[allow(unused)]
|
||||
fn foo() { //~ HELP a return type might be missing here
|
||||
fn foo() { //~ HELP try adding a return type
|
||||
vec!['a'].iter().map(|c| c)
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| NOTE expected `()`, found `Map<Iter<'_, char>, ...>`
|
||||
|
@ -10,10 +10,10 @@ help: consider using a semicolon here
|
||||
|
|
||||
LL | vec!['a'].iter().map(|c| c);
|
||||
| +
|
||||
help: a return type might be missing here
|
||||
help: try adding a return type
|
||||
|
|
||||
LL | fn foo() -> _ {
|
||||
| ++++
|
||||
LL | fn foo() -> impl Iterator<Item = &char> {
|
||||
| ++++++++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user