Skip to content
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

Suggest replacing named lifetime with 'static #51513

Closed
wants to merge 2 commits into from

Conversation

estebank
Copy link
Contributor

warning: unnecessary lifetime parameter `'a`
  --> file.rs:11:14
   |
11 | fn foo<'c, 'a: 'static, 'b, 'd>(_x: &'a str) -> &'a str {
   |            ^^^^^^^^^^^
help: you can use the `'static` lifetime directly, in place of `'a`
   |
11 | fn foo<'c, 'b, 'd>(_x: &'static str) -> &'static str {
   |           --            ^^^^^^^          ^^^^^^^

warning: unnecessary lifetime parameter `'a`
  --> file.rs:14:9
   |
14 | fn bar<'a: 'static>(_x: &'a str) -> &'a str {
   |        ^^^^^^^^^^^
help: you can use the `'static` lifetime directly, in place of `'a`
   |
14 | fn bar(_x: &'static str) -> &'static str {
   |      --     ^^^^^^^          ^^^^^^^

cc #36179

@rust-highfive
Copy link
Collaborator

r? @michaelwoerister

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 12, 2018
```
warning: unnecessary lifetime parameter `'a`
  --> file.rs:11:14
   |
11 | fn foo<'c, 'a: 'static, 'b, 'd>(_x: &'a str) -> &'a str {
   |            ^^^^^^^^^^^
help: you can use the `'static` lifetime directly, in place of `'a`
   |
11 | fn foo<'c, 'b, 'd>(_x: &'static str) -> &'static str {
   |           --            ^^^^^^^          ^^^^^^^

warning: unnecessary lifetime parameter `'a`
  --> file.rs:14:9
   |
14 | fn bar<'a: 'static>(_x: &'a str) -> &'a str {
   |        ^^^^^^^^^^^
help: you can use the `'static` lifetime directly, in place of `'a`
   |
14 | fn bar(_x: &'static str) -> &'static str {
   |      --     ^^^^^^^          ^^^^^^^
```
@estebank estebank changed the title Suggest replacing named lifetime with 'static [wip] Suggest replacing named lifetime with 'static Jun 12, 2018
@estebank
Copy link
Contributor Author

r? @nikomatsakis

@estebank

This comment has been minimized.

@estebank
Copy link
Contributor Author

@pietroalbini
Copy link
Member

Ping from triage @nikomatsakis! This PR needs your review.

@estebank
Copy link
Contributor Author

Ping.

@nikomatsakis
Copy link
Contributor

@estebank I'm not entirely sure how this is related to #36179 -- it seems like a distinct problem. Do we think that it's common to write 'a: 'static? I do it sometimes as a kind of type-system hack, but I'm not sure if it is something that arises "in the wild".

@nikomatsakis
Copy link
Contributor

Overall, this seems like a bit more code than I would have expected; it feels like there should be a lighterweight way to detect this condition.

@nikomatsakis
Copy link
Contributor

Well, I guess that making the edit is part of the hard part...

@estebank
Copy link
Contributor Author

This code can probably be cleaned quite a bit, but wanted to get some feedback on wether this is worthwhile to begin with.

This doesn't fix #36179, but by providing a suggestion for lifetimes the risk of someone writing '&str is much lower. I used this case in particular to start experimenting on how suggestions for changing multiple lifetimes would look like. If we're ok with the output (and the increased amount of code to be able to get and operate over the lifetime spans), this would only be the first of many other suggestions being reworked from pure text to structured suggestion.

@@ -1662,6 +1669,137 @@ pub struct Ty {
pub hir_id: HirId,
}

impl Ty {
pub fn lifetimes(&self) -> Vec<Lifetime> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we use a visitor for this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what is this used for? It seems like it doesn't handle shadowing (which, I guess, we disallow at present, so maybe that's ok).

(I was thinking of types like for<'a> fn(&'a u32), which mention 'a, but not the same 'a as might be in scope outside... but as I said at present we do disallow such shadowing)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's only used to gather all the lifetime spans in the argument and return tys that match the name being checked.

@nikomatsakis
Copy link
Contributor

I see. I think the output looks good. I'm not sure if there is a more light-weight way to get it.

@nikomatsakis
Copy link
Contributor

I made one suggestion that would help to remove a lot of the boilerplate (using a visitor)

@estebank
Copy link
Contributor Author

CC #44506 (same mechanism can be used to suggest the proposed output).

@bors
Copy link
Contributor

bors commented Jun 21, 2018

☔ The latest upstream changes (presumably #48149) made this pull request unmergeable. Please resolve the merge conflicts.

@estebank estebank added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 21, 2018
Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, @estebank -- now that I understand better what you were going for, I think this looks pretty nice. It seems like we should (A) rewrite to use a visitor, (B) make the vector construction lazy, and (C) add a helper fn, but otherwise this seems like a nice POC. (We could/should fix shadowing too but that is less urgent since it is currently illegal anyway)

@@ -1441,6 +1446,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
.collect();

let next_early_index = index + generics.ty_params().count() as u32;
let mut arg_lifetimes = vec![];
for input in &decl.inputs {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This vector is only used in the case of lint/error, right? I'm not sure how I feel about building it eagerly -- maybe we can convert this into a closure or a trait or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, I'll see what I can do about it.

self.resolve_lifetime_ref(bound);
);

// all the use spans for this lifetime in arguments to be replaced
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should extract this into a helper fn, but the basic idea seems pretty good 💯

@nikomatsakis
Copy link
Contributor

As an example where shadowing could be relevant though:

fn foo<'a: 'static>(x: for<'a> fn(&'a u32)) { }

@estebank
Copy link
Contributor Author

The output for

fn foo<'a: 'static>(x: for<'a> fn(&'a u32)) { }

is

warning: unnecessary lifetime parameter `'a`
 --> file.rs:1:8
  |
1 | fn foo<'a: 'static>(x: for<'a> fn(&'a u32)) { }
  |        ^^^^^^^^^^^
help: you can use the `'static` lifetime directly, in place of `'a`
  |
1 | fn foo(x: for<'a> fn(&'static u32)) { }
  |      --               ^^^^^^^

error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
 --> file.rs:1:28
  |
1 | fn foo<'a: 'static>(x: for<'a> fn(&'a u32)) { }
  |        --                  ^^ lifetime 'a already in scope
  |        |
  |        first declared here

@nikomatsakis
Copy link
Contributor

@estebank

The output for...

hmm, that seems suboptimal, do you agree? I think it'd be pretty easy to fix -- in the lifetimes() function that gathers up the lifetimes that appear in a type, when we encounter types with for<'a> binders, we should remove the things that appear in the binders from the result. (i.e., we only want the "free" lifetimes of the type)

@estebank
Copy link
Contributor Author

Agree with your comments. I tried rebasing to see how hard it would be to include the feedback and the codebase diverged significantly. I'll get back to this later.

@nikomatsakis
Copy link
Contributor

@estebank should we close the PR in the mean time?

@estebank
Copy link
Contributor Author

Closing until I get back to this.

@estebank estebank closed this Jun 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants