Skip to content

Unused warnings#3819

Merged
hdgarrood merged 9 commits into
purescript:masterfrom
nwolverson:unused-warnings
Apr 11, 2021
Merged

Unused warnings#3819
hdgarrood merged 9 commits into
purescript:masterfrom
nwolverson:unused-warnings

Conversation

@nwolverson
Copy link
Copy Markdown
Contributor

Addresses some parts of #1670, specifically unused let/where bound values, binders, un-exported value declarations.

There are some warnings-tests but I've yet to throw this at a decent-sized codebase to see how much it picks up.

Will need update to CONTRIBUTORS before merging.

@natefaubion
Copy link
Copy Markdown
Contributor

Looks like there's a lot of diff churn due to automatic formatting.

@nwolverson
Copy link
Copy Markdown
Contributor Author

Yeah apparently I didn't manage to fork off latest or I spent long enough doing so that things have moved on, I'll do some rebasing. In the meantime, the changes in Linter however are all new - I didn't couple it to the existing pass there

@nwolverson nwolverson force-pushed the unused-warnings branch 2 times, most recently from c325257 to 40c1dd7 Compare March 20, 2020 11:51
@nwolverson
Copy link
Copy Markdown
Contributor Author

OK, I did do some funky reformat for some reason. This should now be rebased, unfortunately I can't run tests even on master locally since updating to latest.

@natefaubion
Copy link
Copy Markdown
Contributor

You need to delete .test_modules

@nwolverson
Copy link
Copy Markdown
Contributor Author

Thanks, got it passing now. Some reason had to update the golden test for 1 file I didn't touch

@natefaubion
Copy link
Copy Markdown
Contributor

#3808

Comment thread src/Language/PureScript/Linter.hs Outdated
Comment on lines +146 to +147
let n (ValueRef _ ident) = Just ident
n _ = Nothing
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is getValueRef in AST.Declarations

Comment thread src/Language/PureScript/Linter.hs Outdated
Comment on lines +154 to +159
getDeclIdent :: Declaration -> Maybe Ident
getDeclIdent (ValueDeclaration vd) = Just (valdeclIdent vd)
getDeclIdent (ExternDeclaration _ ident _) = Just ident
getDeclIdent (TypeInstanceDeclaration _ _ _ ident _ _ _ _) = Just ident
getDeclIdent BindingGroupDeclaration{} = internalError "lint: binding groups should not be desugared yet."
getDeclIdent _ = Nothing
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is getIdentName <=< declName.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is copied from earlier in the same file actually, oops!


goDecl _ = mempty

go :: SourceSpan -> Expr -> (S.Set Ident, MultipleErrors)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If everythingWithContextOnValues let you get a hold of PositionedValue, could this be implemented in terms of that traversal? Much of this traversal looks like it's reimplementing that, but the only difference is the context is a source span, which you can't get with the current implementation. I don't think it would break anything to expose that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, the main issue with everythingWithContextOnValues is that at the point of binders, we don't want to do something on the binder and the expression under its scope separately and combine them, we want to take the result on the scoped expression then look at that together with the binder. I guess it would likely be possible to bake more into the context and do all the logic in the combine, but that seems rather contorted, really this is another traversal for capture-aware operations.

(Aside, I originally followed the logic for the type-level version of the same, which inverts to go top-down with the set of so far unused variables - now that was a bunch of make-work...)

@hdgarrood
Copy link
Copy Markdown
Contributor

Just wanted to say I really appreciate you picking this up. I'm sure this will have a hugely positive effect on the codebase I work on (although I guess I won't be able to give it a try until we've released 0.14 and updated at work).

@natefaubion
Copy link
Copy Markdown
Contributor

I think this looks good. Have you tried running it against https://github.com/JordanMartinez/purescript-hail-mary? I would like to get an idea of the number of warnings to expect from this overall. You can use --verbose-stats with psa to get a breakdown.

@JordanMartinez
Copy link
Copy Markdown
Contributor

JordanMartinez commented Apr 11, 2020

@natefaubion I actually just deleted that repo. When I said there were 381 warnings using my master-compatible package set, I found out that many of them were due to # Type being used instead of Row Type. That made me realize that my branch wasn't including all of my work. So, I just finished updating that fork to point to all the work I did previously via the fix-warnings-ps-master-compatible branch.

Since I'm no Bash-fu person, I found that this code made it possible to install all packages in that set:

sudo apt-get install xclip -y
spago ls packages > example.txt && cat example.txt | sed -r "s/([a-zA-Z0-9-]+).*/\1/" | tr '\n' ' ' | xclip -selection c
spago install <CTRL+SHIFT+V>

The current number of warnings is now 377, but not all of them are the "the inferred kind for X is Y. Consider adding a kind signature" warnings.

@natefaubion
Copy link
Copy Markdown
Contributor

natefaubion commented May 4, 2020

I think there are some missing cases, particularly around record puns. When running against the package set, I get warnings for things like children in https://github.com/lumihq/purescript-react-basic/blob/master/src/React/Basic/DOM/Generated.purs#L17481

@natefaubion
Copy link
Copy Markdown
Contributor

This is missing a case for Literal, so it does not work it's way into object or array literals.

@nwolverson
Copy link
Copy Markdown
Contributor Author

I did see the (earlier) comment nate, just not got around to running against that compatible package set - I don't think I was aware of it before

@natefaubion
Copy link
Copy Markdown
Contributor

@nwolverson I made a change to fix this, but I'm not going to presume by pushing to this branch. psa does not work against master currently due to the stderr/stdout switch. I ran a jq script against the error output.

From that above ps-master-compatible branch:

cd src
spago install
spago build > errors.json

and then to generate a table:

jq -r '.warnings | map(select(.errorCode == "UnusedName") | .moduleName) | group_by(.) | map({moduleName: .[0], count: .|length}) | .[] | "\(.moduleName) \(.count)"' errors.json | sort -k2 -n | column -t -s' ' | tail -r

Or to filter specific modules:

jq -r '.warnings | map(select(.errorCode == "UnusedName" and .moduleName == "Halogen.VDom.DOM"))' errors.json

@nwolverson
Copy link
Copy Markdown
Contributor Author

I've updated a bunch of cases here, there were quite a few issues

  • Module self-exports were reporting everything as unused
  • Let bindings with patterns let { x } = e were just broken
  • Object/array literals as @natefaubion said
  • The operator part of binary operator expressions

Looking at that package set now, I'm only finding genuine unused issues - including a surprising number of declarations that are not used or exported :)

Improvements that could be made

  • Source span of unused declarations is the whole file, should at least be the decl

btw @JordanMartinez I have a different spago version apparently but I used this

spago list-packages | awk '{print $1}' | xargs spago install

@nwolverson
Copy link
Copy Markdown
Contributor Author

Rebased on master and fixed golden tests

@nwolverson
Copy link
Copy Markdown
Contributor Author

Updated to avoid warning on variables with _ prefix, this is a common pattern from many languages, discussion on #purescript seemed entirely positive in that regard.

@garyb
Copy link
Copy Markdown
Member

garyb commented Nov 11, 2020

Just curious, what sort of situation is that useful in? We tend to prefix our foreign imports with _ and I'd want the use of those to be considered. I can't really think of a reason I'd want to bypass this check personally. I'm sure there is a reason for it, just not one I've encountered myself.

@nwolverson
Copy link
Copy Markdown
Contributor Author

@garyb the change I just pushed only makes that distinction for locally bound identifiers, rather than top level declarations, I believe, so should not affect the foreign import case. For those top-level decls I don't really see any possible reason to distinguish - why would you want to define a function or import a foreign and not use it, I can only imagine it is dead or intended to be used in future, and a warning is appropriate.

The situation tends to be when pattern matching on multiple arguments, it's often clearer to see what is being ignored rather than seeing _ everywhere. Often when using multiple function heads and ignoring certain arguments in some of them, or passing a lambda which happens to ignore an argument - obviously it's a stylistic choice and depends on the code you write, when running these warnings over an actual codebase I came across a bunch of instances where I would best just replace a discarding binding with _, but others in which I felt the name improves clarity.

The leading underscore is a convention in a number of languages/compilers/linters - e.g. Erlang, Haskell (GHC), Rust, TypeScript, Ruby (Rubocop)

@garyb
Copy link
Copy Markdown
Member

garyb commented Nov 11, 2020

Thanks for the explanation!

@nwolverson
Copy link
Copy Markdown
Contributor Author

Just looking through my open prs - the build failure on this is a timeout - I expect only worth kicking it when looking to merge this.

nwolverson and others added 4 commits March 4, 2021 10:33
* Declarations that are used but not exported
* Variables bound in let/lambda bindings, case patterns, etc which are unused
Comment thread src/Language/PureScript/Linter.hs Outdated
Comment thread src/Language/PureScript/Linter.hs Outdated
(S.Set Ident, MultipleErrors) ->
(S.Set Ident, MultipleErrors) ->
(S.Set Ident, MultipleErrors)
combine (a, b) (c, d) = (S.union a c, b <> d)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this is just <>? Or did you avoid that deliberately for readability?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I imagine this is like this because of the other version in this file which is (S.intersection a c, b <> d) - I think this code originally worked the other way around so the instance wasn't right. I don't think infix combine is readable - I'll change it

Comment thread src/Language/PureScript/Linter.hs Outdated

go _ (PositionedValue ss' _ v1) = go ss' v1

go _ _ = (mempty, mempty)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd quite like to avoid catch-all patterns here, as I think it will be quite easy to forget to update this function if we do add new cases to Expr in the future. Would you mind matching every constructor here?

@hdgarrood
Copy link
Copy Markdown
Contributor

Looks great! I have a few (very minor) comments and then I would be happy to merge this.

nwolverson and others added 2 commits March 12, 2021 10:37
Co-authored-by: Harry Garrood <harry@garrood.me>
@hdgarrood
Copy link
Copy Markdown
Contributor

I'm going to push a commit updating the changelog and then merge this. Thanks!

@hdgarrood hdgarrood merged commit cf82492 into purescript:master Apr 11, 2021
@imcotton
Copy link
Copy Markdown
Contributor

imcotton commented May 2, 2021

joneshf added a commit to joneshf/purescript-option that referenced this pull request May 21, 2021
We move to the latest version of everything.

We're addressing both errors and warnings in this change (because we'd
like to treat warnings like errors anyway). For the most part this is
straight-forward find/replace change. We did have to do something about
the static checks though.

What we did was dump them all into an array and export that single
value. Since there doesn't seem to be any way to define a value at the
top-level that is otherwise unused without it also producing a warning,
we're kind of pigeon-holed into this sort of solution. The only other
option is to remove the static checks, but they've caught way more
issues than is reasonable for the amount of code they are so that feels
like a major step backwards.

It would've been ideal to prefix them with an `_` (like you can do in
other situations), but that's not how things work. For more information,
see this discussion:
purescript/purescript#3819 (comment).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants