Skip to content

Commit fddd397

Browse files
committed
use liberate_late_bound_regions and get types from there
1 parent 68b1e8b commit fddd397

File tree

3 files changed

+58
-40
lines changed

3 files changed

+58
-40
lines changed

clippy_lints/src/iter_without_into_iter.rs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::get_parent_as_impl;
3+
use clippy_utils::source::snippet;
34
use clippy_utils::ty::{implements_trait, make_normalized_projection};
45
use rustc_errors::Applicability;
5-
use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, Mutability, QPath, TyKind};
6-
use rustc_hir_analysis::hir_ty_to_ty;
6+
use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, Mutability, TyKind};
77
use rustc_lint::{LateContext, LateLintPass};
8-
use rustc_middle::ty::print::with_forced_trimmed_paths;
9-
use rustc_middle::ty::{self};
108
use rustc_session::{declare_lint_pass, declare_tool_lint};
119
use rustc_span::sym;
1210

@@ -59,6 +57,7 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
5957
}
6058

6159
fn check_for_mutability(cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>, expected_mtbl: Mutability) {
60+
let item_did = item.owner_id.to_def_id();
6261
let (borrow_prefix, name, expected_implicit_self) = match expected_mtbl {
6362
Mutability::Not => ("&", "iter", ImplicitSelfKind::ImmRef),
6463
Mutability::Mut => ("&mut ", "iter_mut", ImplicitSelfKind::MutRef),
@@ -67,38 +66,32 @@ fn check_for_mutability(cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>, ex
6766
if let ImplItemKind::Fn(sig, _) = item.kind
6867
&& let FnRetTy::Return(ret) = sig.decl.output
6968
&& is_nameable_in_impl_trait(ret)
70-
&& cx.tcx.generics_of(item.owner_id.def_id).params.is_empty()
69+
&& cx.tcx.generics_of(item_did).params.is_empty()
7170
&& sig.decl.implicit_self == expected_implicit_self
7271
&& sig.decl.inputs.len() == 1
7372
&& let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id())
7473
&& imp.of_trait.is_none()
75-
&& let TyKind::Path(QPath::Resolved(_, path)) = imp.self_ty.kind
76-
&& let Some(ty_did) = path.res.opt_def_id()
77-
&& let middle_ty = cx.tcx.type_of(ty_did).skip_binder()
78-
&& let ref_ty = cx.tcx.mk_ty_from_kind(ty::Ref(cx.tcx.lifetimes.re_erased, middle_ty, expected_mtbl))
79-
&& let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
80-
&& let bound_vars = cx.tcx.late_bound_vars(item.hir_id())
81-
// We need to erase late bounds regions so that `-> Iter<'_, T>` works
82-
&& let ret_middle_ty = cx.tcx.erase_late_bound_regions(
83-
ty::Binder::bind_with_vars(hir_ty_to_ty(cx.tcx, ret), bound_vars)
74+
&& let sig = cx.tcx.liberate_late_bound_regions(
75+
item_did,
76+
cx.tcx.fn_sig(item_did).skip_binder()
8477
)
78+
&& let ref_ty = sig.inputs()[0]
79+
&& let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
80+
&& let ret_ty = sig.output()
8581
// Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator`
8682
// *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs)
87-
&& implements_trait(cx, ret_middle_ty, into_iter_did, &[])
88-
&& let Some(ret_iter_ty) = make_normalized_projection(
83+
&& implements_trait(cx, ret_ty, into_iter_did, &[])
84+
&& let Some(iter_ty) = make_normalized_projection(
8985
cx.tcx,
9086
cx.param_env,
9187
into_iter_did,
9288
sym!(Item),
93-
[ret_middle_ty]
89+
[ret_ty],
9490
)
9591
// Only lint if the `IntoIterator` impl doesn't actually exist
9692
&& !implements_trait(cx, ref_ty, into_iter_did, &[])
9793
{
98-
let (self_ty_snippet, into_iter_snippet) = with_forced_trimmed_paths!((
99-
format!("{borrow_prefix}{}", cx.tcx.def_path_str(ty_did)),
100-
cx.tcx.def_path_str(into_iter_did)
101-
));
94+
let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, ".."));
10295

10396
span_lint_and_then(
10497
cx,
@@ -116,16 +109,15 @@ fn check_for_mutability(cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>, ex
116109

117110
let sugg = format!(
118111
"
119-
impl {into_iter_snippet} for {self_ty_snippet} {{
120-
type IntoIter = {ret_middle_ty};
121-
type Iter = {ret_iter_ty};
112+
impl IntoIterator for {self_ty_snippet} {{
113+
type IntoIter = {ret_ty};
114+
type Iter = {iter_ty};
122115
fn into_iter() -> Self::IntoIter {{
123116
self.iter()
124117
}}
125118
}}
126119
"
127120
);
128-
129121
diag.span_suggestion_verbose(
130122
span_behind_impl,
131123
format!("consider implementing `IntoIterator` for `{self_ty_snippet}`"),

tests/ui/iter_without_into_iter.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ fn main() {
6363
todo!()
6464
}
6565
}
66+
struct S5<T>(T);
67+
impl<T> S5<T> {
68+
pub fn iter(&self) -> std::slice::Iter<'static, T> {
69+
todo!()
70+
}
71+
}
6672
}
6773
{
6874
struct S<T>(T);

tests/ui/iter_without_into_iter.stderr

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ LL + }
4242
LL + }
4343
|
4444

45-
error: `iter` method without an `IntoIterator` impl for `&S`
45+
error: `iter` method without an `IntoIterator` impl for `&S<'a>`
4646
--> $DIR/iter_without_into_iter.rs:30:13
4747
|
4848
LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> {
@@ -51,10 +51,10 @@ LL | | self.0.iter()
5151
LL | | }
5252
| |_____________^
5353
|
54-
help: consider implementing `IntoIterator` for `&S`
54+
help: consider implementing `IntoIterator` for `&S<'a>`
5555
|
5656
LL ~
57-
LL + impl IntoIterator for &S {
57+
LL + impl IntoIterator for &S<'a> {
5858
LL + type IntoIter = std::slice::Iter<'_, u8>;
5959
LL + type Iter = &u8;
6060
LL + fn into_iter() -> Self::IntoIter {
@@ -63,7 +63,7 @@ LL + }
6363
LL + }
6464
|
6565

66-
error: `iter_mut` method without an `IntoIterator` impl for `&mut S`
66+
error: `iter_mut` method without an `IntoIterator` impl for `&mut S<'a>`
6767
--> $DIR/iter_without_into_iter.rs:34:13
6868
|
6969
LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
@@ -72,10 +72,10 @@ LL | | self.0.iter_mut()
7272
LL | | }
7373
| |_____________^
7474
|
75-
help: consider implementing `IntoIterator` for `&mut S`
75+
help: consider implementing `IntoIterator` for `&mut S<'a>`
7676
|
7777
LL ~
78-
LL + impl IntoIterator for &mut S {
78+
LL + impl IntoIterator for &mut S<'a> {
7979
LL + type IntoIter = std::slice::IterMut<'_, u8>;
8080
LL + type Iter = &mut u8;
8181
LL + fn into_iter() -> Self::IntoIter {
@@ -84,19 +84,39 @@ LL + }
8484
LL + }
8585
|
8686

87-
error: `iter` method without an `IntoIterator` impl for `&S`
88-
--> $DIR/iter_without_into_iter.rs:70:13
87+
error: `iter` method without an `IntoIterator` impl for `&S5<T>`
88+
--> $DIR/iter_without_into_iter.rs:68:13
89+
|
90+
LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> {
91+
LL | | todo!()
92+
LL | | }
93+
| |_____________^
94+
|
95+
help: consider implementing `IntoIterator` for `&S5<T>`
96+
|
97+
LL ~
98+
LL + impl IntoIterator for &S5<T> {
99+
LL + type IntoIter = std::slice::Iter<'static, T>;
100+
LL + type Iter = &T;
101+
LL + fn into_iter() -> Self::IntoIter {
102+
LL + self.iter()
103+
LL + }
104+
LL + }
105+
|
106+
107+
error: `iter` method without an `IntoIterator` impl for `&S<T>`
108+
--> $DIR/iter_without_into_iter.rs:76:13
89109
|
90110
LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> {
91111
LL | |
92112
LL | | todo!()
93113
LL | | }
94114
| |_____________^
95115
|
96-
help: consider implementing `IntoIterator` for `&S`
116+
help: consider implementing `IntoIterator` for `&S<T>`
97117
|
98118
LL ~
99-
LL + impl IntoIterator for &S {
119+
LL + impl IntoIterator for &S<T> {
100120
LL + type IntoIter = std::slice::Iter<'_, T>;
101121
LL + type Iter = &T;
102122
LL + fn into_iter() -> Self::IntoIter {
@@ -105,19 +125,19 @@ LL + }
105125
LL + }
106126
|
107127

108-
error: `iter_mut` method without an `IntoIterator` impl for `&mut S`
109-
--> $DIR/iter_without_into_iter.rs:74:13
128+
error: `iter_mut` method without an `IntoIterator` impl for `&mut S<T>`
129+
--> $DIR/iter_without_into_iter.rs:80:13
110130
|
111131
LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
112132
LL | |
113133
LL | | todo!()
114134
LL | | }
115135
| |_____________^
116136
|
117-
help: consider implementing `IntoIterator` for `&mut S`
137+
help: consider implementing `IntoIterator` for `&mut S<T>`
118138
|
119139
LL ~
120-
LL + impl IntoIterator for &mut S {
140+
LL + impl IntoIterator for &mut S<T> {
121141
LL + type IntoIter = std::slice::IterMut<'_, T>;
122142
LL + type Iter = &mut T;
123143
LL + fn into_iter() -> Self::IntoIter {
@@ -126,5 +146,5 @@ LL + }
126146
LL + }
127147
|
128148

129-
error: aborting due to 6 previous errors
149+
error: aborting due to 7 previous errors
130150

0 commit comments

Comments
 (0)