Skip to content

Commit 55805ab

Browse files
Make is_suggestable work on all TypeFoldable
1 parent 9c47afe commit 55805ab

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -2509,11 +2509,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
25092509
labeled_user_string
25102510
);
25112511
let pred = format!("{}: {}", bound_kind, sub);
2512-
let suggestion = format!(
2513-
"{} {}",
2514-
generics.add_where_or_trailing_comma(),
2515-
pred,
2516-
);
2512+
let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
25172513
err.span_suggestion(
25182514
generics.tail_span_for_predicate_suggestion(),
25192515
"consider adding a where clause",

compiler/rustc_middle/src/ty/diagnostics.rs

+47-14
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, TypeSuperFoldable, 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

+18-22
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;
@@ -358,11 +356,14 @@ fn suggest_restriction<'tcx>(
358356
ty::Param(param) => {
359357
// `fn foo(t: impl Trait)`
360358
// ^^^^^ get this string
361-
param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig))
359+
param.name.as_str().strip_prefix("impl ").map(|s| (s.trim_start().to_string(), sig))
362360
}
363361
_ => None,
364362
})
365363
{
364+
if !trait_pred.is_suggestable_modulo_impl_trait(tcx, &bound_str) {
365+
return;
366+
}
366367
// We know we have an `impl Trait` that doesn't satisfy a required projection.
367368

368369
// Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'
@@ -417,6 +418,9 @@ fn suggest_restriction<'tcx>(
417418
Applicability::MaybeIncorrect,
418419
);
419420
} else {
421+
if !trait_pred.is_suggestable(tcx) {
422+
return;
423+
}
420424
// Trivial case: `T` needs an extra bound: `T: Bound`.
421425
let (sp, suggestion) = match (
422426
generics
@@ -463,16 +467,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
463467
_ => (false, None),
464468
};
465469

466-
let generic_args_have_impl_trait = |args: SubstsRef<'tcx>| -> bool {
467-
args.iter().any(|arg| match arg.unpack() {
468-
GenericArgKind::Type(ty) => match ty.kind() {
469-
ty::Param(param) => param.name.as_str().starts_with("impl"),
470-
_ => false,
471-
},
472-
_ => false,
473-
})
474-
};
475-
476470
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
477471
// don't suggest `T: Sized + ?Sized`.
478472
let mut hir_id = body_id;
@@ -574,6 +568,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
574568
| hir::Node::ImplItem(hir::ImplItem { generics, .. })
575569
if param_ty =>
576570
{
571+
if !trait_pred.skip_binder().trait_ref.substs[1..]
572+
.iter()
573+
.all(|g| g.is_suggestable(self.tcx))
574+
{
575+
return;
576+
}
577577
// Missing generic type parameter bound.
578578
let param_name = self_ty.to_string();
579579
let constraint = with_no_trimmed_paths!(
@@ -603,13 +603,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
603603
| hir::ItemKind::TraitAlias(generics, _)
604604
| hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
605605
..
606-
}) if !param_ty
607-
&& !generic_args_have_impl_trait(trait_pred.skip_binder().trait_ref.substs) =>
608-
{
606+
}) if !param_ty => {
609607
// Missing generic type parameter bound.
610-
let param_name = self_ty.to_string();
611-
let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
612-
if suggest_arbitrary_trait_bound(generics, &mut err, &param_name, &constraint) {
608+
if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
613609
return;
614610
}
615611
}

compiler/rustc_typeck/src/astconv/generics.rs

+1-1
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

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
2727
use rustc_middle::middle::stability::AllowUnstable;
2828
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
2929
use rustc_middle::ty::GenericParamDefKind;
30-
use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable};
30+
use rustc_middle::ty::{
31+
self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable,
32+
};
3133
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
3234
use rustc_span::edition::Edition;
3335
use rustc_span::lev_distance::find_best_match_for_name;

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

+1-1
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

+1-5
Original file line numberDiff line numberDiff line change
@@ -817,11 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
817817
trait bound{s}",
818818
s = pluralize!(obligations.len())
819819
),
820-
format!(
821-
"{} {}",
822-
add_where_or_comma,
823-
obligations.join(", ")
824-
),
820+
format!("{} {}", add_where_or_comma, obligations.join(", ")),
825821
Applicability::MaybeIncorrect,
826822
);
827823
}

compiler/rustc_typeck/src/collect.rs

+1-1
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)