Suggest adding self type to method

This commit is contained in:
Michael Goulet 2024-10-31 15:59:44 +00:00
parent 41966e71bc
commit ea4fb7c25c
4 changed files with 55 additions and 7 deletions

View File

@ -210,9 +210,15 @@ pub(crate) struct DependencyOnUnitNeverTypeFallback<'tcx> {
pub sugg: SuggestAnnotations,
}
#[derive(Clone)]
pub(crate) enum SuggestAnnotation {
Unit(Span),
Path(Span),
}
#[derive(Clone)]
pub(crate) struct SuggestAnnotations {
pub suggestion_spans: Vec<Span>,
pub suggestions: Vec<SuggestAnnotation>,
}
impl Subdiagnostic for SuggestAnnotations {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
@ -220,13 +226,26 @@ impl Subdiagnostic for SuggestAnnotations {
diag: &mut Diag<'_, G>,
_: &F,
) {
if self.suggestion_spans.is_empty() {
if self.suggestions.is_empty() {
return;
}
let mut suggestions = vec![];
for suggestion in self.suggestions {
match suggestion {
SuggestAnnotation::Unit(span) => {
suggestions.push((span, "()".to_string()));
}
SuggestAnnotation::Path(span) => {
suggestions.push((span.shrink_to_lo(), "<() as ".to_string()));
suggestions.push((span.shrink_to_hi(), ">".to_string()));
}
}
}
diag.multipart_suggestion_verbose(
"use `()` annotations to avoid fallback changes",
self.suggestion_spans.into_iter().map(|span| (span, String::from("()"))).collect(),
suggestions,
Applicability::MachineApplicable,
);
}

View File

@ -8,6 +8,7 @@ use rustc_data_structures::graph::{self};
use rustc_data_structures::unord::{UnordBag, UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::Visitor;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
use rustc_session::lint;
@ -573,7 +574,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// For each diverging var, look through the HIR for a place to give it
// a type annotation. We do this per var because we only really need one
// per var.
let suggestion_spans = diverging_vids
let suggestions = diverging_vids
.iter()
.copied()
.filter_map(|vid| {
@ -582,16 +583,17 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
VidVisitor { reachable_vids, fcx: self }.visit_expr(body.value).break_value()
})
.collect();
errors::SuggestAnnotations { suggestion_spans }
errors::SuggestAnnotations { suggestions }
}
}
/// Try to collect a useful suggestion to preserve fallback to `()`.
struct VidVisitor<'a, 'tcx> {
reachable_vids: FxHashSet<ty::TyVid>,
fcx: &'a FnCtxt<'a, 'tcx>,
}
impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
type Result = ControlFlow<Span>;
type Result = ControlFlow<errors::SuggestAnnotation>;
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) -> Self::Result {
if let hir::TyKind::Infer = hir_ty.kind
@ -599,10 +601,25 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
&& let Some(vid) = self.fcx.root_vid(ty)
&& self.reachable_vids.contains(&vid)
{
return ControlFlow::Break(hir_ty.span);
return ControlFlow::Break(errors::SuggestAnnotation::Unit(hir_ty.span));
}
hir::intravisit::walk_ty(self, hir_ty)
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let Res::Def(DefKind::AssocFn, def_id) = path.res
&& self.fcx.tcx.trait_of_item(def_id).is_some()
&& let self_ty = self.fcx.typeck_results.borrow().node_args(expr.hir_id).type_at(0)
&& let Some(vid) = self.fcx.root_vid(self_ty)
&& self.reachable_vids.contains(&vid)
&& let [.., trait_segment, _method_segment] = path.segments
{
let span = path.span.shrink_to_lo().to(trait_segment.ident.span);
return ControlFlow::Break(errors::SuggestAnnotation::Path(span));
}
hir::intravisit::walk_expr(self, expr)
}
}
#[derive(Debug, Copy, Clone)]

View File

@ -13,6 +13,10 @@ note: in edition 2024, the requirement `!: Default` will fail
LL | true => Default::default(),
| ^^^^^^^^^^^^^^^^^^
= note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
help: use `()` annotations to avoid fallback changes
|
LL | true => <() as Default>::default(),
| ++++++ +
warning: this function depends on never type fallback being `()`
--> $DIR/never-type-fallback-breaking.rs:27:1

View File

@ -13,6 +13,10 @@ note: in edition 2024, the requirement `!: UnitDefault` will fail
LL | x = UnitDefault::default();
| ^^^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
help: use `()` annotations to avoid fallback changes
|
LL | x = <() as UnitDefault>::default();
| ++++++ +
warning: this function depends on never type fallback being `()`
--> $DIR/diverging-fallback-control-flow.rs:42:1
@ -28,6 +32,10 @@ note: in edition 2024, the requirement `!: UnitDefault` will fail
|
LL | x = UnitDefault::default();
| ^^^^^^^^^^^^^^^^^^^^^^
help: use `()` annotations to avoid fallback changes
|
LL | x = <() as UnitDefault>::default();
| ++++++ +
warning: 2 warnings emitted