From ec35b840e71c34ea2d7c7a59a9c69ce0f44c4740 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 21 Dec 2016 12:11:42 +0100 Subject: Tweak the way annotations are represented in desugaring Need to be careful not to read a classfile before a compilation unit defining the annotation is entered. --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 30 +++++++++++++++++----- compiler/src/dotty/tools/dotc/typer/FrontEnd.scala | 16 +++++++++++- compiler/test/dotc/scala-collections.blacklist | 3 --- compiler/test/dotc/scala-collections.whitelist | 2 +- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 13ddff08c..211683c0a 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -7,6 +7,7 @@ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, F import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import Decorators._ import language.higherKinds +import typer.FrontEnd import collection.mutable.ListBuffer import util.Property import reporting.diagnostic.messages._ @@ -363,7 +364,7 @@ object desugar { if (mods.is(Abstract) || hasRepeatedParam) Nil // cannot have default arguments for repeated parameters, hence copy method is not issued else { def copyDefault(vparam: ValDef) = - makeAnnotated(defn.UncheckedVarianceAnnot, refOfDef(vparam)) + makeAnnotated("scala.annotation.unchecked.uncheckedVariance", refOfDef(vparam)) val copyFirstParams = derivedVparamss.head.map(vparam => cpy.ValDef(vparam)(rhs = copyDefault(vparam))) val copyRestParamss = derivedVparamss.tail.nestedMap(vparam => @@ -559,7 +560,7 @@ object desugar { case VarPattern(named, tpt) => derivedValDef(original, named, tpt, rhs, mods) case _ => - val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs) + val rhsUnchecked = makeAnnotated("scala.unchecked", rhs) val vars = getVariables(pat) val isMatchingTuple: Tree => Boolean = { case Tuple(es) => es.length == vars.length @@ -688,11 +689,28 @@ object desugar { new ImplicitFunction(params, body) } - /** Add annotation with class `cls` to tree: - * tree @cls + /** Add annotation to tree: + * tree @fullName + * + * The annotation is usually represented as a TypeTree referring to the class + * with the given name `fullName`. However, if the annotation matches a file name + * that is still to be entered, the annotation is represented as a cascade of `Selects` + * following `fullName`. This is necessary so that we avoid reading an annotation from + * the classpath that is also compiled from source. */ - def makeAnnotated(cls: Symbol, tree: Tree)(implicit ctx: Context) = - Annotated(tree, untpd.New(untpd.TypeTree(cls.typeRef), Nil)) + def makeAnnotated(fullName: String, tree: Tree)(implicit ctx: Context) = { + val parts = fullName.split('.') + val ttree = ctx.typerPhase match { + case phase: FrontEnd if phase.stillToBeEntered(parts.last) => + val prefix = + ((Ident(nme.ROOTPKG): Tree) /: parts.init)((qual, name) => + Select(qual, name.toTermName)) + Select(prefix, parts.last.toTypeName) + case _ => + TypeTree(ctx.requiredClass(fullName).typeRef) + } + Annotated(tree, untpd.New(ttree, Nil)) + } private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = { val vdef = ValDef(named.name.asTermName, tpt, rhs) diff --git a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala index cd374e32c..90ffbcdae 100644 --- a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala +++ b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala @@ -19,6 +19,15 @@ class FrontEnd extends Phase { override def isTyper = true import ast.tpd + /** The contexts for compilation units that are parsed but not yet entered */ + private var remaining: List[Context] = Nil + + /** Does a source file ending with `.scala` belong to a compilation unit + * that is parsed but not yet entered? + */ + def stillToBeEntered(name: String): Boolean = + remaining.exists(_.compilationUnit.toString.endsWith(name + ".scala")) + def monitor(doing: String)(body: => Unit)(implicit ctx: Context) = try body catch { @@ -75,7 +84,12 @@ class FrontEnd extends Phase { } unitContexts foreach (parse(_)) record("parsedTrees", ast.Trees.ntrees) - unitContexts.foreach(enterSyms(_)) + unitContexts.foreach(ctx => println(ctx.compilationUnit)) + remaining = unitContexts + while (remaining.nonEmpty) { + enterSyms(remaining.head) + remaining = remaining.tail + } unitContexts.foreach(enterAnnotations(_)) unitContexts.foreach(typeCheck(_)) record("total trees after typer", ast.Trees.ntrees) diff --git a/compiler/test/dotc/scala-collections.blacklist b/compiler/test/dotc/scala-collections.blacklist index 342317825..7d3008bbc 100644 --- a/compiler/test/dotc/scala-collections.blacklist +++ b/compiler/test/dotc/scala-collections.blacklist @@ -1,8 +1,5 @@ ## Errors having to do with bootstrap -../scala-scala/src/library/scala/annotation/unchecked/uncheckedVariance.scala -#java.lang.AssertionError: assertion failed: data race? overwriting symbol of type scala.annotation.unchecked.uncheckedVariance, - ../scala-scala/src/library/scala/Function1.scala ../scala-scala/src/library/scala/Function2.scala # Cyclic reference because of @specialized annotation diff --git a/compiler/test/dotc/scala-collections.whitelist b/compiler/test/dotc/scala-collections.whitelist index 1590120d3..cb7fd29b9 100644 --- a/compiler/test/dotc/scala-collections.whitelist +++ b/compiler/test/dotc/scala-collections.whitelist @@ -537,7 +537,7 @@ ../scala-scala/src/library/scala/annotation/tailrec.scala ../scala-scala/src/library/scala/annotation/TypeConstraint.scala ../scala-scala/src/library/scala/annotation/unchecked/uncheckedStable.scala -#../scala-scala/src/library/scala/annotation/unchecked/uncheckedVariance.scala +../scala-scala/src/library/scala/annotation/unchecked/uncheckedVariance.scala ../scala-scala/src/library/scala/annotation/unspecialized.scala ../scala-scala/src/library/scala/annotation/varargs.scala -- cgit v1.2.3