Skip to content

Add annotations phase #1693

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

Merged
merged 9 commits into from
Dec 1, 2016
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Nov 10, 2016

New phase for entering annotations

If we want to do annotation macros right, we need to add
annotations before completing definitions. This commit achieves
that by adding a new "phase" between index and typecheck.

Also: Fixes #1647 be tweaking the context in which we evaluate annotation argumnents

Review by @liufengyun or @olafurpg

*
* TODO: Once we have fully bootstrapped, I would prefer if we expressed
* unimport with an `override` modifier, and generalized it to all imports.
* I believe this would be more transparent than the curren set of conditions. E.g.
Copy link
Contributor

@felixmulder felixmulder Nov 10, 2016

Choose a reason for hiding this comment

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

Super-nitpick: curren => current :)

Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

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

Another concern is about how annotation macros fit into this picture. Current implementation doesn't allow expansion during annotate phase, as it returns Unit. Adding/removing top-level definitions in macros can also be very tricky with indexing.

It seems a relative reliable way is to expand macros inside expand during indexing phase -- and we need to restrict that annotation macros can't be used in the same compilation run when they're defined.

original match {
case original: MemberDef => addAnnotations(denot.symbol, original)
case _ =>
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not clear to me why we need to addAnnotations again for ValDef and DefDef here, as they are already handled by a call to annotate when they are indexed (in ClassCompleter and typedBlockStats).

Is it just for breaking the cyclic dependence between Predef and deprecated in test compileStdLib as commented before? Then maybe a comment here as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Annotations, and classes or objects containing them, might be completed out of order as part of the annotations phase. It seems necessary that these symbols get annotated on completion, or otherwise we'd introduce a compilation order dependency.

//
// `@ann` is evaluated in the context just outside `C`, where the `a.b`
// import is visible but the `d.e` import is forgotten. This measure is necessary
// in order to avoid cycles.
Copy link
Contributor

Choose a reason for hiding this comment

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

The lexical scope for @ann is very counter-intuitive. If it's only some rare erroneous programs cause cycles, it seems justified to keep the intuitive scoping rules as a trade off.

Copy link

Choose a reason for hiding this comment

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

@odersky Can you provide an example of a program that leads to spurious cycles?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@xeno-by I had lots of failing test cases in the regression tests. They failed with CyclicReference errors. I did not keep track of which ones.

@@ -6,7 +6,7 @@ import java.io.{
File, PrintWriter, PrintStream, StringWriter, Writer, OutputStream,
ByteArrayOutputStream => ByteOutputStream
}
import java.lang.{Class, ClassLoader}
import java.lang.{Class, ClassLoader, Thread, System, StringBuffer}
Copy link
Member

Choose a reason for hiding this comment

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

Is this something that should be handled by the rewriting tool?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm missing context, what exactly do you mean by "this"?

Copy link
Member

Choose a reason for hiding this comment

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

See commit message "Honor the new scheme where any explicit import of a root import will disable the root import."

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, that sounds like a prime candidate for rewriting. I opened scalacenter/scalafix#21

@@ -1135,7 +1137,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(implicit ctx: Context): Unit = {
// necessary to force annotation trees to be computed.
sym.annotations.foreach(_.ensureCompleted)
val annotCtx = ctx.outersIterator.dropWhile(_.owner == sym).next
lazy val annotCtx = {
Copy link
Member

Choose a reason for hiding this comment

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

Would be nice to add a comment explaining why this is needed as the commit message does.

* that are already added to the symbol.
*/
def addAnnotations(sym: Symbol, stat: MemberDef)(implicit ctx: Context) = {
// (1) The context in which an annotation of a top-evel class or module is evaluated
Copy link
Member

Choose a reason for hiding this comment

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

typo: top-evel -> top-level

// (1) The context in which an annotation of a top-evel class or module is evaluated
// is the closest enclosing context which has the enclosing package as owner.
// (2) The context in which an annotation for any other symbol is evaluated is the
// closest enclosing context which has the owner of the class enclpsing the symbol as owner.
Copy link
Member

Choose a reason for hiding this comment

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

typo: enclpsing -> enclosing

@@ -6,7 +6,7 @@ import java.io.{
File, PrintWriter, PrintStream, StringWriter, Writer, OutputStream,
ByteArrayOutputStream => ByteOutputStream
}
import java.lang.{Class, ClassLoader}
import java.lang.{Class, ClassLoader, Thread, System, StringBuffer}
Copy link
Member

Choose a reason for hiding this comment

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

See commit message "Honor the new scheme where any explicit import of a root import will disable the root import."

@odersky
Copy link
Contributor Author

odersky commented Nov 24, 2016

Rebased to master

Had duplications of `import` before.
Also: add import info when printing contexts.
We got a hard to track down error when changing to the new
annotations elaboration scheme (should be in the next commit):

When running `testNonCyclic`, `DotClass` was not found in object Trees
even though it was imported from `util`. It turned out that the import
was ignored because the `util` symbol was completing.

This commit adds a warning when this happens. The warning currently applies
only to named imports because several false negatives were encountered if
we do this also on wildcard imports. I.e. we get a warning, but the searched
after symbol is not a member of the wildcard qualifier.

This commit also refactors namedImportRef, so that `site` is only
computed when the name to reseolve appears in the selector list.
That change made the previously observed error go away because less
is now forced.
Honor the new scheme where any explicit import of a
root import will disable the root import.
It was broken before, since it worked only on wildcard imports.
Got a "next on empty iterator" exception before.
If we want to do annotation macros right, we need to add
annotations before completing definitions. This commit achieves
that by adding a new "phase" between index and typecheck.
Need to evaluate annotation arguments in an expression context, since
classes defined in asuch arguments should not be entered into enclosing
class.

Fixes scala#1647
This PR also fixes scala#1649
@odersky odersky force-pushed the add-annotations-phase branch from bf84725 to e1d79a2 Compare December 1, 2016 13:01
@odersky odersky merged commit 47d2084 into scala:master Dec 1, 2016
@allanrenucci allanrenucci deleted the add-annotations-phase branch December 14, 2017 15:01
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.

6 participants