mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 23:12:02 +00:00
Make is_suggestable work on all TypeFoldable
This commit is contained in:
parent
9c47afe9fa
commit
55805ab473
@ -2509,11 +2509,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
labeled_user_string
|
||||
);
|
||||
let pred = format!("{}: {}", bound_kind, sub);
|
||||
let suggestion = format!(
|
||||
"{} {}",
|
||||
generics.add_where_or_trailing_comma(),
|
||||
pred,
|
||||
);
|
||||
let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
|
||||
err.span_suggestion(
|
||||
generics.tail_span_for_predicate_suggestion(),
|
||||
"consider adding a where clause",
|
||||
|
@ -3,8 +3,8 @@
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::ty::{
|
||||
fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, Ty, TyCtxt,
|
||||
TypeVisitor,
|
||||
fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
|
||||
PolyTraitPredicate, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor,
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -73,31 +73,53 @@ impl<'tcx> Ty<'tcx> {
|
||||
_ => self.is_simple_ty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the type can be safely suggested during error recovery.
|
||||
pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
|
||||
pub trait IsSuggestable<'tcx> {
|
||||
fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool;
|
||||
|
||||
fn is_suggestable_modulo_impl_trait(self, tcx: TyCtxt<'tcx>, bound_str: &str) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx, T> IsSuggestable<'tcx> for T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
self.visit_with(&mut IsSuggestableVisitor { tcx, bound_str: None }).is_continue()
|
||||
}
|
||||
|
||||
fn is_suggestable_modulo_impl_trait(self, tcx: TyCtxt<'tcx>, bound_str: &str) -> bool {
|
||||
self.visit_with(&mut IsSuggestableVisitor { tcx, bound_str: Some(bound_str) }).is_continue()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_arbitrary_trait_bound(
|
||||
pub fn suggest_arbitrary_trait_bound<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
generics: &hir::Generics<'_>,
|
||||
err: &mut Diagnostic,
|
||||
param_name: &str,
|
||||
constraint: &str,
|
||||
trait_pred: PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
|
||||
match (param, param_name) {
|
||||
(Some(_), "Self") => return false,
|
||||
_ => {}
|
||||
if !trait_pred.is_suggestable(tcx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let param_name = trait_pred.skip_binder().self_ty().to_string();
|
||||
let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
|
||||
let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
|
||||
|
||||
// Skip, there is a param named Self
|
||||
if param.is_some() && param_name == "Self" {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Suggest a where clause bound for a non-type parameter.
|
||||
err.span_suggestion_verbose(
|
||||
generics.tail_span_for_predicate_suggestion(),
|
||||
&format!(
|
||||
"consider {} `where` clause, but there might be an alternative better way to express \
|
||||
this requirement",
|
||||
if generics.has_where_clause_token { "extending the" } else { "introducing a" },
|
||||
if generics.has_where_clause_token { "extending the" } else { "introducing a" },
|
||||
),
|
||||
format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint),
|
||||
Applicability::MaybeIncorrect,
|
||||
@ -395,11 +417,12 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IsSuggestableVisitor<'tcx> {
|
||||
pub struct IsSuggestableVisitor<'tcx, 's> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
bound_str: Option<&'s str>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
||||
impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx, '_> {
|
||||
type BreakTy = ();
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
@ -438,6 +461,16 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Param(param) => {
|
||||
if let Some(found_bound_str) =
|
||||
param.name.as_str().strip_prefix("impl ").map(|s| s.trim_start())
|
||||
{
|
||||
if self.bound_str.map_or(true, |bound_str| bound_str != found_bound_str) {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,9 @@ use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
||||
use rustc_middle::hir::map;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
subst::{GenericArgKind, SubstsRef},
|
||||
suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
|
||||
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
|
||||
TypeFoldable,
|
||||
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
|
||||
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
|
||||
ToPredicate, Ty, TyCtxt, TypeFoldable,
|
||||
};
|
||||
use rustc_middle::ty::{TypeAndMut, TypeckResults};
|
||||
use rustc_session::Limit;
|
||||
@ -358,11 +356,14 @@ fn suggest_restriction<'tcx>(
|
||||
ty::Param(param) => {
|
||||
// `fn foo(t: impl Trait)`
|
||||
// ^^^^^ get this string
|
||||
param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig))
|
||||
param.name.as_str().strip_prefix("impl ").map(|s| (s.trim_start().to_string(), sig))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
if !trait_pred.is_suggestable_modulo_impl_trait(tcx, &bound_str) {
|
||||
return;
|
||||
}
|
||||
// We know we have an `impl Trait` that doesn't satisfy a required projection.
|
||||
|
||||
// Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'
|
||||
@ -417,6 +418,9 @@ fn suggest_restriction<'tcx>(
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
if !trait_pred.is_suggestable(tcx) {
|
||||
return;
|
||||
}
|
||||
// Trivial case: `T` needs an extra bound: `T: Bound`.
|
||||
let (sp, suggestion) = match (
|
||||
generics
|
||||
@ -463,16 +467,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
_ => (false, None),
|
||||
};
|
||||
|
||||
let generic_args_have_impl_trait = |args: SubstsRef<'tcx>| -> bool {
|
||||
args.iter().any(|arg| match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => match ty.kind() {
|
||||
ty::Param(param) => param.name.as_str().starts_with("impl"),
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
})
|
||||
};
|
||||
|
||||
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
|
||||
// don't suggest `T: Sized + ?Sized`.
|
||||
let mut hir_id = body_id;
|
||||
@ -574,6 +568,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
| hir::Node::ImplItem(hir::ImplItem { generics, .. })
|
||||
if param_ty =>
|
||||
{
|
||||
if !trait_pred.skip_binder().trait_ref.substs[1..]
|
||||
.iter()
|
||||
.all(|g| g.is_suggestable(self.tcx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Missing generic type parameter bound.
|
||||
let param_name = self_ty.to_string();
|
||||
let constraint = with_no_trimmed_paths!(
|
||||
@ -603,13 +603,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
| hir::ItemKind::TraitAlias(generics, _)
|
||||
| hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
|
||||
..
|
||||
}) if !param_ty
|
||||
&& !generic_args_have_impl_trait(trait_pred.skip_binder().trait_ref.substs) =>
|
||||
{
|
||||
}) if !param_ty => {
|
||||
// Missing generic type parameter bound.
|
||||
let param_name = self_ty.to_string();
|
||||
let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
|
||||
if suggest_arbitrary_trait_bound(generics, &mut err, ¶m_name, &constraint) {
|
||||
if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::ty::{
|
||||
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
|
||||
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
|
||||
use rustc_span::{symbol::kw, Span};
|
||||
|
@ -27,7 +27,9 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
|
||||
use rustc_middle::middle::stability::AllowUnstable;
|
||||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::ty::{
|
||||
self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable,
|
||||
};
|
||||
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::lev_distance::find_best_match_for_name;
|
||||
|
@ -15,7 +15,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt};
|
||||
use rustc_infer::traits;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, Binder, ToPredicate, Ty};
|
||||
use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
|
@ -817,11 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
trait bound{s}",
|
||||
s = pluralize!(obligations.len())
|
||||
),
|
||||
format!(
|
||||
"{} {}",
|
||||
add_where_or_comma,
|
||||
obligations.join(", ")
|
||||
),
|
||||
format!("{} {}", add_where_or_comma, obligations.join(", ")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::util::Discr;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ReprOptions, ToPredicate};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
|
Loading…
Reference in New Issue
Block a user