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