-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rework use_self impl based on ty::Ty comparison #3410 #5531
rework use_self impl based on ty::Ty comparison #3410 #5531
Conversation
7bbea69
to
15440bb
Compare
ae774b4
to
5020fcf
Compare
clippy_lints/src/use_self.rs
Outdated
if should_check { | ||
let visitor = &mut UseSelfVisitor { | ||
item_path, | ||
let self_ty= hir_ty_to_ty(cx.tcx, item_type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My guess is, that this is causing the ICE in could_be_const.rs
. It's probably some wrong item_type
being passed in, but I'm not sure beyond that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, commenting sections making use of this seems to solve failing test cases.
Could you help me out on this?
I've been trying to debug this without much success. The backtraces are not very helpful and the errors are raised from rustc location I have no understanding of. What is the hir_ty_to_ty
contract? Under which circumstances could this call lead to errors elsewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I can try =) Beyond that, I'm not really sure about how to use hir_ty_to_ty
properly and it's not documented either.
I can see two ways to move a bit forward though:
- Could you try not doing the conversion for
def::Res::SelfTy
? That would look like this:rust-clippy/clippy_lints/src/use_self.rs
Lines 94 to 98 in f2486b3
if let TyKind::Path(QPath::Resolved(_, path)) = &hir_ty.kind { match path.res { def::Res::SelfTy(..) => {}, _ => { if hir_ty_to_ty(self.cx.tcx, hir_ty) == self.self_ty { dbg!
as much as possible around this location and figure out if there's something that looks odd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the problem is located in the visit_ty
method of the visitor. See line 167 mentioned in another comment hereunder.
edf40c4
to
6853f11
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need more help finding a solution for those weird ICEs, let me know and I'll take a closer look.
clippy_lints/src/use_self.rs
Outdated
// @flip1995 found an ast lowering issue in | ||
// https://github.com/rust-lang/rust/blob/master/src/librustc_ast_lowering/path.rs#L142-L162 | ||
{ | ||
span_lint(self.cx, hir_ty.span.with_hi(last_segment.ident.span.lo() - BytePos(2))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per discussion on Discord: Have you tried the SourceMap::span_until_char
method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet :). On the todo list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Span handling improved. See truncate_last_segment
fn.
clippy_lints/src/use_self.rs
Outdated
cx.tcx | ||
.typeck_tables_of(expr.hir_id.owner.to_def_id()) | ||
.node_type(expr.hir_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason, why you don't use Nevermind, this is in a visitor, so you need the cx.tables.expr_ty{_opt}(expr)
?typeck_tables_of
call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is responsible for the ICE in ui/missing_const_for_fn/could_be_const.rs
. Try expr_ty_opt
here to possibly prevent this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, what I forget to tell you, is that you might call cx.tcx.has_typeck_tables(def_id)
before trying to get the typeck tables. At least this is how it's done in most of the rest of Clippy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the cx.tcx.has_typeck_tables(def_id)
tip. I'll give it a try.
typeck_tables_of
is documented in the rustc guide. I tried expr_ty
without success, the tests panicked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If expr_ty
panics, node_ty
will also panic, since expr_ty
calls node_ty
. You have to use if let Some(ty) = tcx.typeck_tables_of(def_id).expr_ty_opt(expr)
, but first make sure to check cx.tcx.has_typeck_tables(def_id)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should have protected all occurrences of type expression queries with has_typeck_tables
. The problem remains.
clippy_lints/src/use_self.rs
Outdated
} | ||
|
||
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { | ||
if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind { | ||
match path.res { | ||
def::Res::SelfTy(..) => {}, | ||
_ => { | ||
if hir_ty_to_ty(self.cx.tcx, hir_ty) == self.self_ty { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commenting out the block starting at line 167 makes the other tests pass. Commenting the inner block starting at the next line 168 instead makes them fail again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could use a little help on this one, I'm a bit clueless :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this call results in a delay_span_bug
here: https://github.com/rust-lang/rust/blob/e91aebc1a3835b9b420da0c021e211175a724b8d/src/librustc_typeck/collect.rs#L309-L312
But this method can only be called, if hir_ty.kind == hir::TyKind::Infer
(Code). Since we're checking that the hir_ty.kind == Path
earlier, this doesn't make any sense.
But it gets weirder. if we insert a dbg!(hir_ty)
or println!("{:?}", hir_ty)
it doesn't panic anymore and the hir_ty.kind
is always printed as TyKind::Path(Resolved)
...
In fact, even a print!("x");
before this line makes the ICE go away. It has to print something though, print!("");
won't work.
Since printf debugging won't help here, I will investigate this further with gdb
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two backtraces of the ICEs for the errors
"bad placeholder type" (eta.rs
, question_mark.rs
)
error: internal compiler error: src/librustc_typeck/collect.rs:311: bad placeholder type
--> tests/ui/eta.rs:116:15
|
116 | Thunk(Box::new(move || option.take().unwrap()()))
| ^^^^^^^^
thread 'rustc' panicked at 'Box<Any>', /home/pkrones/rust/src/libstd/macros.rs:13:23
stack backtrace:
0: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
1: core::fmt::write
2: std::io::Write::write_fmt
3: std::sys_common::backtrace::print
4: std::panicking::default_hook::{{closure}}
5: std::panicking::default_hook
6: <alloc::boxed::Box<F> as core::ops::function::Fn<A>>::call
at /home/pkrones/rust/src/liballoc/boxed.rs:1048
7: clippy_driver::report_clippy_ice
at src/driver.rs:242
8: <clippy_driver::ICE_HOOK as core::ops::deref::Deref>::deref::__static_ref_initialize::{{closure}}
at src/driver.rs:235
9: std::panicking::rust_panic_with_hook
10: std::panicking::begin_panic
11: rustc_errors::HandlerInner::span_bug
12: rustc_errors::Handler::span_bug
13: rustc_middle::util::bug::opt_span_bug_fmt::{{closure}}
14: rustc_middle::ty::context::tls::with_opt::{{closure}}
15: rustc_middle::ty::context::tls::with_opt
16: rustc_middle::util::bug::opt_span_bug_fmt
17: rustc_middle::util::bug::span_bug_fmt
18: <rustc_typeck::collect::ItemCtxt as rustc_typeck::astconv::AstConv>::ty_infer
19: <dyn rustc_typeck::astconv::AstConv>::create_substs_for_ast_path::{{closure}}
20: <dyn rustc_typeck::astconv::AstConv>::create_substs_for_generic_args
21: <dyn rustc_typeck::astconv::AstConv>::create_substs_for_ast_path
22: <dyn rustc_typeck::astconv::AstConv>::ast_path_substs_for_ty
23: <dyn rustc_typeck::astconv::AstConv>::res_to_ty
24: <dyn rustc_typeck::astconv::AstConv>::ast_ty_to_ty
25: rustc_typeck::hir_ty_to_ty
26: <clippy_lints::use_self::ImplVisitor as rustc_hir::intravisit::Visitor>::visit_ty
at clippy_lints/src/use_self.rs:166
...
"unelided lifetime in signature" (crashes/ice-4775.rs
, expect_fun_call.rs
, unit_arg.rs
)
error: internal compiler error: src/librustc_typeck/astconv.rs:182: unelided lifetime in signature --> /home/pkrones/rust/src/libstd/macros.rs:97:28 | 97 | $crate::io::_print($crate::format_args_nl!($($arg)*)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread 'rustc' panicked at 'Box<Any>', /home/pkrones/rust/src/libstd/macros.rs:13:23 stack backtrace:
0: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
1: core::fmt::write
2: std::io::Write::write_fmt
3: std::sys_common::backtrace::print
4: std::panicking::default_hook::{{closure}}
5: std::panicking::default_hook
6: <alloc::boxed::Box<F> as core::ops::function::Fn<A>>::call
at /home/pkrones/rust/src/liballoc/boxed.rs:1048
7: clippy_driver::report_clippy_ice
at src/driver.rs:242
8: <clippy_driver::ICE_HOOK as core::ops::deref::Deref>::deref::__static_ref_initialize::{{closure}}
at src/driver.rs:235
9: std::panicking::rust_panic_with_hook
10: std::panicking::begin_panic
11: rustc_errors::HandlerInner::span_bug
12: rustc_errors::Handler::span_bug
13: rustc_middle::util::bug::opt_span_bug_fmt::{{closure}}
14: rustc_middle::ty::context::tls::with_opt::{{closure}}
15: rustc_middle::ty::context::tls::with_opt
16: rustc_middle::util::bug::opt_span_bug_fmt
17: rustc_middle::util::bug::span_bug_fmt
18: <dyn rustc_typeck::astconv::AstConv>::ast_region_to_region::{{closure}}
19: <dyn rustc_typeck::astconv::AstConv>::ast_region_to_region
20: <dyn rustc_typeck::astconv::AstConv>::create_substs_for_generic_args
21: <dyn rustc_typeck::astconv::AstConv>::create_substs_for_ast_path
22: <dyn rustc_typeck::astconv::AstConv>::ast_path_substs_for_ty
23: <dyn rustc_typeck::astconv::AstConv>::res_to_ty
24: <dyn rustc_typeck::astconv::AstConv>::ast_ty_to_ty
25: rustc_typeck::hir_ty_to_ty
26: <clippy_lints::use_self::ImplVisitor as rustc_hir::intravisit::Visitor>::visit_ty
at clippy_lints/src/use_self.rs:166
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@flip1995 is this a misuse of the api or a compiler bug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite a few. I committed the hack and flagged all FN in the ui test use_self.rs
file with a FIXME
comment.
I left a commented block explaining the problem and indicating which code to use in order to resolve most false negatives. We could open a follow-up issue to track the unresolved ICEs.
I think we're better off with those false negatives rather than the false positives of the previous implementation. The lint will catch less cases, but will be more accurate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could open a follow-up issue to track the unresolved ICEs.
We can't merge a PR that introduces ICEs. Did you mean for the FPs?
I think we're better off with those false negatives rather than the false positives of the previous implementation. The lint will catch less cases, but will be more accurate.
Agreed ✔️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't merge a PR that introduces ICEs. Did you mean for the FPs?
In the current patch state that passes all tests, a block of the implementation is commented out to avoid ICEs. We could create a follow-up ticket to investigate this and try to make that part work without errors. That would solve most FNs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh now the dogfood_clippy test throws compiler errors 😞.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sadly tells us, that it is not possible to fix the ICEs by excluding specific TyKind
s. I kind of expected that, since TyKind
is a recursive enum, so just checking the top level type doesn't really help, since some subtype could still be problematic.
I will look in to this closer, when I have some time. I hope I get to it rather sooner than later.
77c4a1f
to
a7a2bc7
Compare
clippy_lints/src/use_self.rs
Outdated
fn truncate_last_segment<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, sp: Span) -> Span { | ||
match snippet_opt(cx, sp) { | ||
Some(snippet) => match snippet.rfind("::") { | ||
Some(bidx) => sp.with_hi(sp.lo() + BytePos(bidx as u32)), | ||
None => sp, | ||
}, | ||
None => sp, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unwise when paths can have generic args anywhere. You probably want to instead rely on the fact that segments have their own spans (AFAIK) so you can check that the path's overall span and the span of the last segment have the same hi
and then use that to "carve out" the last segment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried to depend more on paths subelements own span. I had issues with QPath::TypeRelative
. @flip1995 spotted issues in the ast lowering. See the associated comment in the patch line 172 and the discussion in discord.
But agreed that this will fail upon generics nested paths. I'll add a test case and look for options to deal with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Span handling improved. See span_lint_until_last_segment
. I added a nested path test case. It fails to compile due to the reason @flip1995 analyzed above.
b3a4c24
to
6ad21e7
Compare
6ad21e7
to
69afa6f
Compare
☔ The latest upstream changes (presumably #5763) made this pull request unmergeable. Please resolve the merge conflicts. |
69afa6f
to
fc7ee75
Compare
I think I found the problem with
where the So I changed use_self impl and didn't use the hir_ty_to_ty on fn bodies. That cause a couple of FN regressions which I marked with I propose this pr is merged like this (with another round of review). The newly introduced FNs can be addressed in a next iteration. cc @flip1995 |
070317a
to
f4c3d47
Compare
Oh man I never got back to this PR... Thanks for looking into it again! Let's do a @bors try run. I'll review tomorrow, it's already 1am again... |
…itive, r=<try> rework use_self impl based on ty::Ty comparison #3410 `use_self` lint refactoring. As suggested by `@eddyb` , implement the lint based on `ty::Ty` comparison instead of `hir::Path` checks. This PR introduces negative regressions. The cases were covered in the previous implementation. See the test file. It fixes #3410, #2843, #3859, #4734 and #4140. Should fix #4143 (example doesn't compile). #4305 false positive seems also fixed but the uitest fails to compile the unmodified test case in `use_self.rs.fixed`. Implements #5078. Generally the implementation checks are done at mir level and offers higher guarantees against false positives. It is probably fixing other unreported false positives. changelog: fix use_self generics false positives
☀️ Try build successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm with your description of the error behind hir_ty_to_ty
I guess, that we're just in the completely wrong ItemCtx
, because we're using visitors with the context from some impl
item.
What if we don't use visitors, but use the lint framework and every time we encounter an ItemKind::Impl
, we push the self_ty
on the stack and if we leave the ItemKind::Impl
, we pop the self_ty
from the stack. I'll try if that works.
clippy_lints/src/use_self.rs
Outdated
// The following block correctly identifies applicable lint locations | ||
// but `hir_ty_to_ty` calls cause odd ICEs. | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment still applicable here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I'll remove it.
So my idea to rewrite this and removing the visitors seems to work. My rewrite is at the state, that it fixed all the |
Rework use_self impl based on ty::Ty comparison #3410 | Take 2 This builds on top of #5531 I already reviewed and approved the commits by `@montrivo.` So only the review of my commits should be necessary. I would also appreciate your review `@montrivo,` since you are familiar with the challenges here. Fixes #3410 and Fixes #4143 (same problem) Fixes #2843 Fixes #3859 Fixes #4734 and fixes #6221 Fixes #4305 Fixes #5078 (even at expression level now 🎉) Fixes #3881 and Fixes #4887 (same problem) Fixes #3909 Not yet: #4140 (test added) All the credit for the fixes goes to `@montrivo.` I only refactored and copy and pasted his code. changelog: rewrite [`use_self`] lint and fix multiple (8) FPs. One to go.
Rework use_self impl based on ty::Ty comparison #3410 | Take 2 This builds on top of #5531 I already reviewed and approved the commits by `@montrivo.` So only the review of my commits should be necessary. I would also appreciate your review `@montrivo,` since you are familiar with the challenges here. Fixes #3410 and Fixes #4143 (same problem) Fixes #2843 Fixes #3859 Fixes #4734 and fixes #6221 Fixes #4305 Fixes #5078 (even at expression level now 🎉) Fixes #3881 and Fixes #4887 (same problem) Fixes #3909 Not yet: #4140 (test added) All the credit for the fixes goes to `@montrivo.` I only refactored and copy and pasted his code. changelog: rewrite [`use_self`] lint and fix multiple (8) FPs. One to go.
Rework use_self impl based on ty::Ty comparison #3410 | Take 2 This builds on top of #5531 I already reviewed and approved the commits by `@montrivo.` So only the review of my commits should be necessary. I would also appreciate your review `@montrivo,` since you are familiar with the challenges here. Fixes #3410 and Fixes #4143 (same problem) Fixes #2843 Fixes #3859 Fixes #4734 and fixes #6221 Fixes #4305 Fixes #5078 (even at expression level now 🎉) Fixes #3881 and Fixes #4887 (same problem) Fixes #3909 Not yet: #4140 (test added) All the credit for the fixes goes to `@montrivo.` I only refactored and copy and pasted his code. changelog: rewrite [`use_self`] lint and fix multiple (8) FPs. One to go.
use_self
lint refactoring. As suggested by @eddyb , implement the lint based onty::Ty
comparison instead ofhir::Path
checks.This PR introduces negative regressions. The cases were covered in the previous implementation. See the test file.
It fixes #3410, #2843, #3859, #4734 and #4140. Should fix #4143 (example doesn't compile). #4305 false positive seems also fixed but the uitest fails to compile the unmodified test case in
use_self.rs.fixed
. Implements #5078.Generally the implementation checks are done at mir level and offers higher guarantees against false positives. It is probably fixing other unreported false positives.
changelog: fix use_self generics false positives