mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Suggest adding self type to method
This commit is contained in:
parent
41966e71bc
commit
ea4fb7c25c
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user