Skip to content

Commit b4a6549

Browse files
And also suggest for qpaths
1 parent 0eeb4db commit b4a6549

8 files changed

+151
-0
lines changed

compiler/rustc_hir_typeck/src/errors.rs

+11
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ pub(crate) enum SuggestAnnotation {
215215
Unit(Span),
216216
Path(Span),
217217
Local(Span),
218+
Turbo(Span, usize, usize),
218219
}
219220

220221
#[derive(Clone)]
@@ -244,6 +245,16 @@ impl Subdiagnostic for SuggestAnnotations {
244245
SuggestAnnotation::Local(span) => {
245246
suggestions.push((span, ": ()".to_string()));
246247
}
248+
SuggestAnnotation::Turbo(span, n_args, idx) => suggestions.push((
249+
span,
250+
format!(
251+
"::<{}>",
252+
(0..n_args)
253+
.map(|i| if i == idx { "()" } else { "_" })
254+
.collect::<Vec<_>>()
255+
.join(", "),
256+
),
257+
)),
247258
}
248259
}
249260

compiler/rustc_hir_typeck/src/fallback.rs

+68
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_data_structures::unord::{UnordBag, UnordMap, UnordSet};
99
use rustc_hir as hir;
1010
use rustc_hir::HirId;
1111
use rustc_hir::def::{DefKind, Res};
12+
use rustc_hir::def_id::DefId;
1213
use rustc_hir::intravisit::Visitor;
1314
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
1415
use rustc_session::lint;
@@ -592,10 +593,45 @@ struct VidVisitor<'a, 'tcx> {
592593
reachable_vids: FxHashSet<ty::TyVid>,
593594
fcx: &'a FnCtxt<'a, 'tcx>,
594595
}
596+
impl<'tcx> VidVisitor<'_, 'tcx> {
597+
fn suggest_for_segment(
598+
&self,
599+
arg_segment: &'tcx hir::PathSegment<'tcx>,
600+
def_id: DefId,
601+
id: HirId,
602+
) -> ControlFlow<errors::SuggestAnnotation> {
603+
if arg_segment.args.is_none()
604+
&& let Some(all_args) = self.fcx.typeck_results.borrow().node_args_opt(id)
605+
&& let generics = self.fcx.tcx.generics_of(def_id)
606+
&& let args = &all_args[generics.parent_count..]
607+
// We can't turbofish consts :(
608+
&& args.iter().all(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_) | ty::GenericArgKind::Lifetime(_)))
609+
{
610+
let n_tys = args
611+
.iter()
612+
.filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
613+
.count();
614+
for (idx, arg) in args.iter().enumerate() {
615+
if let Some(ty) = arg.as_type()
616+
&& let Some(vid) = self.fcx.root_vid(ty)
617+
&& self.reachable_vids.contains(&vid)
618+
{
619+
return ControlFlow::Break(errors::SuggestAnnotation::Turbo(
620+
arg_segment.ident.span.shrink_to_hi(),
621+
n_tys,
622+
idx,
623+
));
624+
}
625+
}
626+
}
627+
ControlFlow::Continue(())
628+
}
629+
}
595630
impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
596631
type Result = ControlFlow<errors::SuggestAnnotation>;
597632

598633
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) -> Self::Result {
634+
// Try to replace `_` with `()`.
599635
if let hir::TyKind::Infer = hir_ty.kind
600636
&& let ty = self.fcx.typeck_results.borrow().node_type(hir_ty.hir_id)
601637
&& let Some(vid) = self.fcx.root_vid(ty)
@@ -606,7 +642,32 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
606642
hir::intravisit::walk_ty(self, hir_ty)
607643
}
608644

645+
fn visit_qpath(
646+
&mut self,
647+
qpath: &'tcx rustc_hir::QPath<'tcx>,
648+
id: HirId,
649+
_span: Span,
650+
) -> Self::Result {
651+
let arg_segment = match qpath {
652+
hir::QPath::Resolved(_, path) => {
653+
path.segments.last().expect("paths should have a segment")
654+
}
655+
hir::QPath::TypeRelative(_, segment) => segment,
656+
hir::QPath::LangItem(..) => {
657+
return hir::intravisit::walk_qpath(self, qpath, id);
658+
}
659+
};
660+
// Alternatively, try to turbofish `::<_, (), _>` (ignoring lifetimes,
661+
// since we don't need to turbofish those; they'll be inferred).
662+
// FIXME: Same logic could work for types...
663+
if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id() {
664+
self.suggest_for_segment(arg_segment, def_id, id)?;
665+
}
666+
hir::intravisit::walk_qpath(self, qpath, id)
667+
}
668+
609669
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
670+
// Try to suggest adding an explicit qself `()` to a trait method path.
610671
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
611672
&& let Res::Def(DefKind::AssocFn, def_id) = path.res
612673
&& self.fcx.tcx.trait_of_item(def_id).is_some()
@@ -618,6 +679,13 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
618679
let span = path.span.shrink_to_lo().to(trait_segment.ident.span);
619680
return ControlFlow::Break(errors::SuggestAnnotation::Path(span));
620681
}
682+
// Or else turbofishing the method
683+
if let hir::ExprKind::MethodCall(segment, ..) = expr.kind
684+
&& let Some(def_id) =
685+
self.fcx.typeck_results.borrow().type_dependent_def_id(expr.hir_id)
686+
{
687+
self.suggest_for_segment(segment, def_id, expr.hir_id)?;
688+
}
621689
hir::intravisit::walk_expr(self, expr)
622690
}
623691

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

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ note: in edition 2024, the requirement `!: Default` will fail
3232
|
3333
LL | deserialize()?;
3434
| ^^^^^^^^^^^^^
35+
help: use `()` annotations to avoid fallback changes
36+
|
37+
LL | deserialize::<()>()?;
38+
| ++++++
3539

3640
warning: 2 warnings emitted
3741

tests/ui/never_type/dependency-on-fallback-to-unit.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ note: in edition 2024, the requirement `!: Default` will fail
3232
|
3333
LL | deserialize()?;
3434
| ^^^^^^^^^^^^^
35+
help: use `()` annotations to avoid fallback changes
36+
|
37+
LL | deserialize::<()>()?;
38+
| ++++++
3539

3640
warning: 2 warnings emitted
3741

tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr

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

1721
warning: 1 warning emitted
1822

tests/ui/never_type/fallback-closure-ret.nofallback.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ note: in edition 2024, the requirement `!: Bar` will fail
1313
LL | foo(|| panic!());
1414
| ^^^^^^^^^^^^^^^^
1515
= note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
16+
help: use `()` annotations to avoid fallback changes
17+
|
18+
LL | foo::<(), _>(|| panic!());
19+
| +++++++++
1620

1721
warning: 1 warning emitted
1822

tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr

+28
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ LL | unsafe { mem::zeroed() }
88
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
99
= help: specify the type explicitly
1010
= note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
11+
help: use `()` annotations to avoid fallback changes
12+
|
13+
LL | unsafe { mem::zeroed::<()>() }
14+
| ++++++
1115

1216
warning: never type fallback affects this call to an `unsafe` function
1317
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:30:13
@@ -18,6 +22,10 @@ LL | core::mem::transmute(Zst)
1822
= warning: this will change its meaning in a future release!
1923
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
2024
= help: specify the type explicitly
25+
help: use `()` annotations to avoid fallback changes
26+
|
27+
LL | core::mem::transmute::<_, ()>(Zst)
28+
| +++++++++
2129

2230
warning: never type fallback affects this union access
2331
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:47:18
@@ -38,6 +46,10 @@ LL | unsafe { *ptr::from_ref(&()).cast() }
3846
= warning: this will change its meaning in a future release!
3947
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
4048
= help: specify the type explicitly
49+
help: use `()` annotations to avoid fallback changes
50+
|
51+
LL | unsafe { *ptr::from_ref(&()).cast::<()>() }
52+
| ++++++
4153

4254
warning: never type fallback affects this call to an `unsafe` function
4355
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:18
@@ -48,6 +60,10 @@ LL | unsafe { internally_create(x) }
4860
= warning: this will change its meaning in a future release!
4961
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
5062
= help: specify the type explicitly
63+
help: use `()` annotations to avoid fallback changes
64+
|
65+
LL | unsafe { internally_create::<()>(x) }
66+
| ++++++
5167

5268
warning: never type fallback affects this call to an `unsafe` function
5369
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:97:18
@@ -58,6 +74,10 @@ LL | unsafe { zeroed() }
5874
= warning: this will change its meaning in a future release!
5975
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
6076
= help: specify the type explicitly
77+
help: use `()` annotations to avoid fallback changes
78+
|
79+
LL | let zeroed = mem::zeroed::<()>;
80+
| ++++++
6181

6282
warning: never type fallback affects this `unsafe` function
6383
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:92:22
@@ -68,6 +88,10 @@ LL | let zeroed = mem::zeroed;
6888
= warning: this will change its meaning in a future release!
6989
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
7090
= help: specify the type explicitly
91+
help: use `()` annotations to avoid fallback changes
92+
|
93+
LL | let zeroed = mem::zeroed::<()>;
94+
| ++++++
7195

7296
warning: never type fallback affects this `unsafe` function
7397
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:115:17
@@ -78,6 +102,10 @@ LL | let f = internally_create;
78102
= warning: this will change its meaning in a future release!
79103
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
80104
= help: specify the type explicitly
105+
help: use `()` annotations to avoid fallback changes
106+
|
107+
LL | let f = internally_create::<()>;
108+
| ++++++
81109

82110
warning: never type fallback affects this call to an `unsafe` method
83111
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:140:13

tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr

+28
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ LL | unsafe { mem::zeroed() }
88
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
99
= help: specify the type explicitly
1010
= note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
11+
help: use `()` annotations to avoid fallback changes
12+
|
13+
LL | unsafe { mem::zeroed::<()>() }
14+
| ++++++
1115

1216
error: never type fallback affects this call to an `unsafe` function
1317
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:30:13
@@ -18,6 +22,10 @@ LL | core::mem::transmute(Zst)
1822
= warning: this will change its meaning in a future release!
1923
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
2024
= help: specify the type explicitly
25+
help: use `()` annotations to avoid fallback changes
26+
|
27+
LL | core::mem::transmute::<_, ()>(Zst)
28+
| +++++++++
2129

2230
error: never type fallback affects this union access
2331
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:47:18
@@ -38,6 +46,10 @@ LL | unsafe { *ptr::from_ref(&()).cast() }
3846
= warning: this will change its meaning in a future release!
3947
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
4048
= help: specify the type explicitly
49+
help: use `()` annotations to avoid fallback changes
50+
|
51+
LL | unsafe { *ptr::from_ref(&()).cast::<()>() }
52+
| ++++++
4153

4254
error: never type fallback affects this call to an `unsafe` function
4355
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:18
@@ -48,6 +60,10 @@ LL | unsafe { internally_create(x) }
4860
= warning: this will change its meaning in a future release!
4961
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
5062
= help: specify the type explicitly
63+
help: use `()` annotations to avoid fallback changes
64+
|
65+
LL | unsafe { internally_create::<()>(x) }
66+
| ++++++
5167

5268
error: never type fallback affects this call to an `unsafe` function
5369
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:97:18
@@ -58,6 +74,10 @@ LL | unsafe { zeroed() }
5874
= warning: this will change its meaning in a future release!
5975
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
6076
= help: specify the type explicitly
77+
help: use `()` annotations to avoid fallback changes
78+
|
79+
LL | let zeroed = mem::zeroed::<()>;
80+
| ++++++
6181

6282
error: never type fallback affects this `unsafe` function
6383
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:92:22
@@ -68,6 +88,10 @@ LL | let zeroed = mem::zeroed;
6888
= warning: this will change its meaning in a future release!
6989
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
7090
= help: specify the type explicitly
91+
help: use `()` annotations to avoid fallback changes
92+
|
93+
LL | let zeroed = mem::zeroed::<()>;
94+
| ++++++
7195

7296
error: never type fallback affects this `unsafe` function
7397
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:115:17
@@ -78,6 +102,10 @@ LL | let f = internally_create;
78102
= warning: this will change its meaning in a future release!
79103
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
80104
= help: specify the type explicitly
105+
help: use `()` annotations to avoid fallback changes
106+
|
107+
LL | let f = internally_create::<()>;
108+
| ++++++
81109

82110
error: never type fallback affects this call to an `unsafe` method
83111
--> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:140:13

0 commit comments

Comments
 (0)