Skip to content

Commit ea4fb7c

Browse files
Suggest adding self type to method
1 parent 41966e7 commit ea4fb7c

4 files changed

Lines changed: 55 additions & 7 deletions

File tree

‎compiler/rustc_hir_typeck/src/errors.rs‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,23 +210,42 @@ pub(crate) struct DependencyOnUnitNeverTypeFallback<'tcx> {
210210
pubsugg:SuggestAnnotations,
211211
}
212212

213+
#[derive(Clone)]
214+
pub(crate)enumSuggestAnnotation{
215+
Unit(Span),
216+
Path(Span),
217+
}
218+
213219
#[derive(Clone)]
214220
pub(crate)structSuggestAnnotations{
215-
pubsuggestion_spans:Vec<Span>,
221+
pubsuggestions:Vec<SuggestAnnotation>,
216222
}
217223
implSubdiagnosticforSuggestAnnotations{
218224
fnadd_to_diag_with<G:EmissionGuarantee,F:SubdiagMessageOp<G>>(
219225
self,
220226
diag:&mutDiag<'_,G>,
221227
_:&F,
222228
){
223-
ifself.suggestion_spans.is_empty(){
229+
ifself.suggestions.is_empty(){
224230
return;
225231
}
226232

233+
letmut suggestions = vec![];
234+
for suggestion inself.suggestions{
235+
match suggestion {
236+
SuggestAnnotation::Unit(span) => {
237+
suggestions.push((span,"()".to_string()));
238+
}
239+
SuggestAnnotation::Path(span) => {
240+
suggestions.push((span.shrink_to_lo(),"<() as ".to_string()));
241+
suggestions.push((span.shrink_to_hi(),">".to_string()));
242+
}
243+
}
244+
}
245+
227246
diag.multipart_suggestion_verbose(
228247
"use `()` annotations to avoid fallback changes",
229-
self.suggestion_spans.into_iter().map(|span| (span,String::from("()"))).collect(),
248+
suggestions,
230249
Applicability::MachineApplicable,
231250
);
232251
}

‎compiler/rustc_hir_typeck/src/fallback.rs‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_data_structures::graph::{self};
88
use rustc_data_structures::unord::{UnordBag,UnordMap,UnordSet};
99
use rustc_hir as hir;
1010
use rustc_hir::HirId;
11+
use rustc_hir::def::{DefKind,Res};
1112
use rustc_hir::intravisit::Visitor;
1213
use rustc_middle::ty::{self,Ty,TyCtxt,TypeSuperVisitable,TypeVisitable};
1314
use rustc_session::lint;
@@ -573,7 +574,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
573574
// For each diverging var, look through the HIR for a place to give it
574575
// a type annotation. We do this per var because we only really need one
575576
// per var.
576-
letsuggestion_spans = diverging_vids
577+
letsuggestions = diverging_vids
577578
.iter()
578579
.copied()
579580
.filter_map(|vid| {
@@ -582,27 +583,43 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
582583
VidVisitor{ reachable_vids,fcx:self}.visit_expr(body.value).break_value()
583584
})
584585
.collect();
585-
errors::SuggestAnnotations{suggestion_spans}
586+
errors::SuggestAnnotations{suggestions}
586587
}
587588
}
588589

590+
/// Try to collect a useful suggestion to preserve fallback to `()`.
589591
structVidVisitor<'a,'tcx>{
590592
reachable_vids:FxHashSet<ty::TyVid>,
591593
fcx:&'aFnCtxt<'a,'tcx>,
592594
}
593595
impl<'tcx>Visitor<'tcx>forVidVisitor<'_,'tcx>{
594-
typeResult = ControlFlow<Span>;
596+
typeResult = ControlFlow<errors::SuggestAnnotation>;
595597

596598
fnvisit_ty(&mutself,hir_ty:&'tcx hir::Ty<'tcx>) -> Self::Result{
597599
iflet hir::TyKind::Infer = hir_ty.kind
598600
&& let ty = self.fcx.typeck_results.borrow().node_type(hir_ty.hir_id)
599601
&& letSome(vid) = self.fcx.root_vid(ty)
600602
&& self.reachable_vids.contains(&vid)
601603
{
602-
returnControlFlow::Break(hir_ty.span);
604+
returnControlFlow::Break(errors::SuggestAnnotation::Unit(hir_ty.span));
603605
}
604606
hir::intravisit::walk_ty(self, hir_ty)
605607
}
608+
609+
fnvisit_expr(&mutself,expr:&'tcx hir::Expr<'tcx>) -> Self::Result{
610+
iflet hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
611+
&& letRes::Def(DefKind::AssocFn, def_id) = path.res
612+
&& self.fcx.tcx.trait_of_item(def_id).is_some()
613+
&& let self_ty = self.fcx.typeck_results.borrow().node_args(expr.hir_id).type_at(0)
614+
&& letSome(vid) = self.fcx.root_vid(self_ty)
615+
&& self.reachable_vids.contains(&vid)
616+
&& let[.., trait_segment, _method_segment] = path.segments
617+
{
618+
let span = path.span.shrink_to_lo().to(trait_segment.ident.span);
619+
returnControlFlow::Break(errors::SuggestAnnotation::Path(span));
620+
}
621+
hir::intravisit::walk_expr(self, expr)
622+
}
606623
}
607624

608625
#[derive(Debug,Copy,Clone)]

‎tests/ui/editions/never-type-fallback-breaking.e2021.stderr‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ note: in edition 2024, the requirement `!: Default` will fail
1313
LL | true => Default::default(),
1414
| ^^^^^^^^^^^^^^^^^^
1515
= note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
16+
help: use `()` annotations to avoid fallback changes
17+
|
18+
LL | true => <() as Default>::default(),
19+
| ++++++ +
1620

1721
warning: this function depends on never type fallback being `()`
1822
--> $DIR/never-type-fallback-breaking.rs:27:1

‎tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ note: in edition 2024, the requirement `!: UnitDefault` will fail
1313
LL | x = UnitDefault::default();
1414
| ^^^^^^^^^^^^^^^^^^^^^^
1515
= note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
16+
help: use `()` annotations to avoid fallback changes
17+
|
18+
LL | x = <() as UnitDefault>::default();
19+
| ++++++ +
1620

1721
warning: this function depends on never type fallback being `()`
1822
--> $DIR/diverging-fallback-control-flow.rs:42:1
@@ -28,6 +32,10 @@ note: in edition 2024, the requirement `!: UnitDefault` will fail
2832
|
2933
LL | x = UnitDefault::default();
3034
| ^^^^^^^^^^^^^^^^^^^^^^
35+
help: use `()` annotations to avoid fallback changes
36+
|
37+
LL | x = <() as UnitDefault>::default();
38+
| ++++++ +
3139

3240
warning: 2 warnings emitted
3341

0 commit comments

Comments
 (0)