-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Implement unused (renamed to ghost terms) #3342
Conversation
ab32456
to
35b7541
Compare
test performance please |
performance test scheduled: 1 job(s) in queue, 0 running. |
performance test failed: Error line number: 16 [check /data/workspace/bench/logs/pull-3342-10-19-18.14.out for more information] |
test performance please |
performance test scheduled: 2 job(s) in queue, 1 running. |
performance test failed: Error line number: 16 [check /data/workspace/bench/logs/pull-3342-10-20-18.49.out for more information] |
I just checked the logs, this PR failed |
331f06f
to
975b36f
Compare
Rebased and changed all |
I would add to the TODO list:
|
ea541a6
to
bd4b6dd
Compare
d6b4c56
to
a1354a8
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.
More to come...
/* Tree transform */ | ||
|
||
override def transformTypeDef(tree: TypeDef)(implicit ctx: Context): tree.type = { | ||
if (tree.symbol.is(UnusedCommon)) |
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(Unused)
. UnusedCommon
should never be used in an is
check.
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.
Done
|
||
override def transformTypeDef(tree: TypeDef)(implicit ctx: Context): tree.type = { | ||
if (tree.symbol.is(UnusedCommon)) | ||
ctx.error(tree.symbol.showKind + " cannot be unused", tree.pos) |
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 this belongs not in this phase, but where we check the other flags whether they make sense.
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.
Done
} | ||
|
||
private def isUnusedContext(implicit ctx: Context): Boolean = | ||
ctx.owner.ownersIterator.exists(_.is(Unused)) // TODO make context mode? |
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.
Or put it in the store, yes.
@@ -0,0 +1,102 @@ | |||
package dotty.tools.dotc.transform | |||
|
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 it's better to implement these checks as a top-down traversal in PostTyper. It's inherently a top-down algorithm not a bottom-up one.
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 will try this in PostTyper. My first approach was in typer and I quickly realized it was a mistake because these failures influenced typing desitions. Hence decided to do it in an isolated miniphase.
@@ -2,17 +2,17 @@ package dotty.tools.dotc.transform | |||
|
|||
import dotty.tools.dotc.ast.tpd | |||
import dotty.tools.dotc.core.Contexts._ | |||
import dotty.tools.dotc.core.NameKinds._ | |||
import dotty.tools.dotc.core.Symbols._ | |||
import dotty.tools.dotc.core.Types._ | |||
import dotty.tools.dotc.transform.MegaPhase.MiniPhase | |||
import dotty.tools.dotc.typer.EtaExpansion | |||
|
|||
import scala.collection.mutable.ListBuffer | |||
|
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 need to have a discussion whether we want to do this. The whole point of unused
is to avoid generating code. So if we lift most arguments we miss that point. If we assume a precise effect analysis we could lift arguments if the argument is pure only. But we do not have such an effect analysis.
An alternative is to always drop unused arguments. In a sense unused arguments are then treated similarly to pattern guards - the compiler is allowed to assume they are pure. In the future, if we have a good effect analysis we could also require that unused arguments are pure (and total?).
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.
Now I'm convinced that we should not evaluate any of the arguments in an unused method. This implies that unused implicits only check for the existence of such implicit and then disregard its computation. For unused arguments that are explicitly stated we should drop them as well but if they are not pure we will emit a warning.
We should not require them to be pure or total, but rather use those as hints in the warnings to point that proof might be unsafe.
def f(unused x: A): B = ???
def g()(unused implicit x: A): B = ???
f(pureA) // pureA is not evaluated
g() // the implicit A for x is not evaluated
g()(pureA) // pureA is not evaluated
f(impureA) // warn that impureA will not be evaluated
g()(impureA) // the implicit A for x is not evaluated
/** This phase removes all references and calls to unused methods or vals | ||
* | ||
* if `unused def f(x1,...,xn): T = ...` | ||
* then `f(y1,...,yn)` --> `y1; ...; yn; (default value for T)` |
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.
Why not use ???
instead of default value? If something goes wrong later you will fail loudly instead of silently, which is better.
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.
These default values are intended to stay there, it is the simplest tree the can be both used when f(...)
is a statement or an expression. These are trivially eliminated by the optimizer.
This way UnusedRefs
does not need to know and special case unused function applications in different positions. The same applies to member selection and identifiers.
f7247a2
to
a06d1a1
Compare
@odersky all changes have been made. The PR is ready for review. |
a50f046
to
c040798
Compare
Rebase |
Just voted in the poll (is it advertised more widely?). FWIW, to me Also, we might want to erase them even though they seem to be used. The current semantics prevent from making |
docs/docs/reference/unused-terms.md
Outdated
present at runtime to be able to do separate compilation and retain binary compatiblity. Unused parameters are contractually | ||
obligated to not be used at runtime, enforcing the essence of evidences on types and allows them to always be optimized away. | ||
|
||
present at runtime to be able to do separate compilation and retain binary compatiblity. |
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.
present at runtime --> present in some form in the generated code
test performance please |
performance test scheduled: 3 job(s) in queue, 1 running. |
performance test failed: Error line number: 24 [check /data/workspace/bench/logs/pull-3342-02-21-14.37.out for more information] |
Really weired name to call this |
I also want to change it. |
Any chance to pick another name, maybe even before the release, since apparently nobody likes |
I could make the change tomorrow morning. |
Renamed to |
println(fun(new Bar)) | ||
} | ||
|
||
def fun(unused foo: Foo): foo.X = { |
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 tests is unsound because it treats ghost values as stable (#4060) /cc @nicolasstucki
Decide or propose keyword that should be used for
unused
: https://goo.gl/forms/UD44AfLUD3dkfnxs2TODO list:
unused
keyword (it can be placed whereimplicit
can be placed)unused
terms are not used where they should notunused
parameters,def
s andval
sunused
parameters and argumentsUnusedFunctionN
andImplcitUnusedFunctionN
forN>0
tests/run/unused-2.scala
with-optimise
UnusedParams
in a miniphase groupunused
) #3410)