Skip to content

Commit 119d314

Browse files
Make is_suggestable work on all TypeFoldable
1 parent e848eca commit 119d314

File tree

8 files changed

+73
-50
lines changed

8 files changed

+73
-50
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,11 +2545,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
25452545
labeled_user_string
25462546
);
25472547
let pred = format!("{}: {}", bound_kind, sub);
2548-
let suggestion = format!(
2549-
"{} {}",
2550-
generics.add_where_or_trailing_comma(),
2551-
pred,
2552-
);
2548+
let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
25532549
err.span_suggestion(
25542550
generics.tail_span_for_predicate_suggestion(),
25552551
"consider adding a where clause",

compiler/rustc_middle/src/ty/diagnostics.rs

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
use std::ops::ControlFlow;
44

55
use crate::ty::{
6-
fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, Ty, TyCtxt,
7-
TypeVisitor,
6+
fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
7+
PolyTraitPredicate, Ty, TyCtxt, TypeVisitor,
88
};
99

1010
use rustc_data_structures::fx::FxHashMap;
@@ -73,31 +73,53 @@ impl<'tcx> Ty<'tcx> {
7373
_ => self.is_simple_ty(),
7474
}
7575
}
76+
}
77+
78+
pub trait IsSuggestable<'tcx> {
79+
fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool;
7680

77-
/// Whether the type can be safely suggested during error recovery.
78-
pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
79-
self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
81+
fn is_suggestable_modulo_impl_trait(self, tcx: TyCtxt<'tcx>, bound_str: &str) -> bool;
82+
}
83+
84+
impl<'tcx, T> IsSuggestable<'tcx> for T
85+
where
86+
T: TypeFoldable<'tcx>,
87+
{
88+
fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
89+
self.visit_with(&mut IsSuggestableVisitor { tcx, bound_str: None }).is_continue()
90+
}
91+
92+
fn is_suggestable_modulo_impl_trait(self, tcx: TyCtxt<'tcx>, bound_str: &str) -> bool {
93+
self.visit_with(&mut IsSuggestableVisitor { tcx, bound_str: Some(bound_str) }).is_continue()
8094
}
8195
}
8296

83-
pub fn suggest_arbitrary_trait_bound(
97+
pub fn suggest_arbitrary_trait_bound<'tcx>(
98+
tcx: TyCtxt<'tcx>,
8499
generics: &hir::Generics<'_>,
85100
err: &mut Diagnostic,
86-
param_name: &str,
87-
constraint: &str,
101+
trait_pred: PolyTraitPredicate<'tcx>,
88102
) -> bool {
103+
if !trait_pred.is_suggestable(tcx) {
104+
return false;
105+
}
106+
107+
let param_name = trait_pred.skip_binder().self_ty().to_string();
108+
let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
89109
let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
90-
match (param, param_name) {
91-
(Some(_), "Self") => return false,
92-
_ => {}
110+
111+
// Skip, there is a param named Self
112+
if param.is_some() && param_name == "Self" {
113+
return false;
93114
}
115+
94116
// Suggest a where clause bound for a non-type parameter.
95117
err.span_suggestion_verbose(
96118
generics.tail_span_for_predicate_suggestion(),
97119
&format!(
98120
"consider {} `where` clause, but there might be an alternative better way to express \
99121
this requirement",
100-
if generics.has_where_clause_token { "extending the" } else { "introducing a" },
122+
if generics.has_where_clause_token { "extending the" } else { "introducing a" },
101123
),
102124
format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint),
103125
Applicability::MaybeIncorrect,
@@ -395,11 +417,12 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
395417
}
396418
}
397419

398-
pub struct IsSuggestableVisitor<'tcx> {
420+
pub struct IsSuggestableVisitor<'tcx, 's> {
399421
tcx: TyCtxt<'tcx>,
422+
bound_str: Option<&'s str>,
400423
}
401424

402-
impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
425+
impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx, '_> {
403426
type BreakTy = ();
404427

405428
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -438,6 +461,16 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
438461
}
439462
}
440463

464+
Param(param) => {
465+
if let Some(found_bound_str) =
466+
param.name.as_str().strip_prefix("impl ").map(|s| s.trim_start())
467+
{
468+
if self.bound_str.map_or(true, |bound_str| bound_str != found_bound_str) {
469+
return ControlFlow::Break(());
470+
}
471+
}
472+
}
473+
441474
_ => {}
442475
}
443476

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@ use rustc_hir::lang_items::LangItem;
2121
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
2222
use rustc_middle::hir::map;
2323
use rustc_middle::ty::{
24-
self,
25-
subst::{GenericArgKind, SubstsRef},
26-
suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
27-
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
28-
TypeFoldable,
24+
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
25+
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
26+
ToPredicate, Ty, TyCtxt, TypeFoldable,
2927
};
3028
use rustc_middle::ty::{TypeAndMut, TypeckResults};
3129
use rustc_session::Limit;
@@ -356,11 +354,14 @@ fn suggest_restriction<'tcx>(
356354
ty::Param(param) => {
357355
// `fn foo(t: impl Trait)`
358356
// ^^^^^ get this string
359-
param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig))
357+
param.name.as_str().strip_prefix("impl ").map(|s| (s.trim_start().to_string(), sig))
360358
}
361359
_ => None,
362360
})
363361
{
362+
if !trait_pred.is_suggestable_modulo_impl_trait(tcx, &bound_str) {
363+
return;
364+
}
364365
// We know we have an `impl Trait` that doesn't satisfy a required projection.
365366

366367
// Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'
@@ -415,6 +416,9 @@ fn suggest_restriction<'tcx>(
415416
Applicability::MaybeIncorrect,
416417
);
417418
} else {
419+
if !trait_pred.is_suggestable(tcx) {
420+
return;
421+
}
418422
// Trivial case: `T` needs an extra bound: `T: Bound`.
419423
let (sp, suggestion) = match (
420424
generics
@@ -461,16 +465,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
461465
_ => (false, None),
462466
};
463467

464-
let generic_args_have_impl_trait = |args: SubstsRef<'tcx>| -> bool {
465-
args.iter().any(|arg| match arg.unpack() {
466-
GenericArgKind::Type(ty) => match ty.kind() {
467-
ty::Param(param) => param.name.as_str().starts_with("impl"),
468-
_ => false,
469-
},
470-
_ => false,
471-
})
472-
};
473-
474468
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
475469
// don't suggest `T: Sized + ?Sized`.
476470
let mut hir_id = body_id;
@@ -572,6 +566,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
572566
| hir::Node::ImplItem(hir::ImplItem { generics, .. })
573567
if param_ty =>
574568
{
569+
if !trait_pred.skip_binder().trait_ref.substs[1..]
570+
.iter()
571+
.all(|g| g.is_suggestable(self.tcx))
572+
{
573+
return;
574+
}
575575
// Missing generic type parameter bound.
576576
let param_name = self_ty.to_string();
577577
let constraint = with_no_trimmed_paths!(
@@ -601,13 +601,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
601601
| hir::ItemKind::TraitAlias(generics, _)
602602
| hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
603603
..
604-
}) if !param_ty
605-
&& !generic_args_have_impl_trait(trait_pred.skip_binder().trait_ref.substs) =>
606-
{
604+
}) if !param_ty => {
607605
// Missing generic type parameter bound.
608-
let param_name = self_ty.to_string();
609-
let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
610-
if suggest_arbitrary_trait_bound(generics, &mut err, &param_name, &constraint) {
606+
if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
611607
return;
612608
}
613609
}

compiler/rustc_typeck/src/astconv/generics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
1313
use rustc_hir::GenericArg;
1414
use rustc_infer::infer::TyCtxtInferExt;
1515
use rustc_middle::ty::{
16-
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
16+
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
1717
};
1818
use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
1919
use rustc_span::{symbol::kw, Span};

compiler/rustc_typeck/src/astconv/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ use rustc_hir::lang_items::LangItem;
2626
use rustc_hir::{GenericArg, GenericArgs};
2727
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
2828
use rustc_middle::ty::GenericParamDefKind;
29-
use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable};
29+
use rustc_middle::ty::{
30+
self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable,
31+
};
3032
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
3133
use rustc_span::edition::Edition;
3234
use rustc_span::lev_distance::find_best_match_for_name;

compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt};
1515
use rustc_infer::traits;
1616
use rustc_middle::lint::in_external_macro;
1717
use rustc_middle::ty::subst::GenericArgKind;
18-
use rustc_middle::ty::{self, Binder, ToPredicate, Ty};
18+
use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
1919
use rustc_span::symbol::{kw, sym};
2020
use rustc_span::Span;
2121
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;

compiler/rustc_typeck/src/check/method/suggest.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -821,11 +821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
821821
trait bound{s}",
822822
s = pluralize!(obligations.len())
823823
),
824-
format!(
825-
"{} {}",
826-
add_where_or_comma,
827-
obligations.join(", ")
828-
),
824+
format!("{} {}", add_where_or_comma, obligations.join(", ")),
829825
Applicability::MaybeIncorrect,
830826
);
831827
}

compiler/rustc_typeck/src/collect.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use rustc_middle::ty::query::Providers;
3939
use rustc_middle::ty::subst::InternalSubsts;
4040
use rustc_middle::ty::util::Discr;
4141
use rustc_middle::ty::util::IntTypeExt;
42-
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
42+
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
4343
use rustc_middle::ty::{ReprOptions, ToPredicate};
4444
use rustc_session::lint;
4545
use rustc_session::parse::feature_err;

0 commit comments

Comments
 (0)