Use suggest_impl_trait in return type suggestion
This commit is contained in:
parent
b3bd7058c1
commit
3764af6119
7 changed files with 68 additions and 60 deletions
|
@ -30,7 +30,7 @@ use rustc_middle::query::Providers;
|
|||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue