Skip to content

Commit

Permalink
Merge pull request #10068 from scalacenter/tasty/support-scala3.2
Browse files Browse the repository at this point in the history
Tasty Reader support Scala 3.2 [ci: last-only]
  • Loading branch information
SethTisue committed Jul 11, 2022
2 parents b6b15d5 + d7f0b8b commit aa579da
Show file tree
Hide file tree
Showing 37 changed files with 566 additions and 174 deletions.
2 changes: 1 addition & 1 deletion project/DottySupport.scala
Expand Up @@ -12,7 +12,7 @@ import sbt.librarymanagement.{
* Settings to support validation of TastyUnpickler against the release of dotty with the matching TASTy version
*/
object TastySupport {
val supportedTASTyRelease = "3.1.2-RC1" // TASTy version 28.1-0
val supportedTASTyRelease = "3.2.0-RC1" // TASTy version 28.2-1
val scala3Compiler = "org.scala-lang" % "scala3-compiler_3" % supportedTASTyRelease
val scala3Library = "org.scala-lang" % "scala3-library_3" % supportedTASTyRelease

Expand Down
46 changes: 26 additions & 20 deletions src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala
Expand Up @@ -706,7 +706,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
rdr.readTerm()(ctx)
}
)(annotCtx.retractMode(IndexScopedStats))
DeferredAnnotation.fromTree(mkTree)
DeferredAnnotation.fromTree(annotSym)(mkTree)
}

private def traceAnnotation(annotStart: Addr, annotSym: Symbol, annotee: Symbol) = TraceInfo[Tree](
Expand Down Expand Up @@ -808,16 +808,18 @@ class TreeUnpickler[Tasty <: TastyUniverse](
val supportedFlags = Extension | Exported | Infix | Given | optFlag(isMacro)(Erased)
checkUnsupportedFlags(repr.unsupportedFlags &~ supportedFlags)
val isCtor = sym.isConstructor
val paramDefss = readParamss()(localCtx).map(_.map(symFromNoCycle))
val typeParams = {
val paramss = readParamss()(localCtx)
val typeClause = {
// A type parameter list must be non-empty and with type symbols
val first = paramDefss.take(1)
if (first.exists(_.exists(_.isType))) first.head else Nil
val first = paramss.take(1)
if (first.exists(_.headOption.exists(nc => symFromNoCycle(nc).isType))) first.head else Nil
}
val valueClauses = paramss.drop(if (typeClause.isEmpty) 0 else 1)
val typeParams = typeClause.map(symFromNoCycle)
val vparamss = {
val vparamSymss = valueClauses.map(_.map(symFromNoCycle))
// A value parameter list may be empty, or filled with term symbols
val valueClauses = paramDefss.drop(if (typeParams.isEmpty) 0 else 1)
val hasTypeParams = valueClauses.exists(_.exists(_.isType))
val hasTypeParams = vparamSymss.exists(_.headOption.exists(_.isType))
unsupportedWhen(hasTypeParams, {
val noun = (
if (isCtor) "constructor"
Expand All @@ -826,7 +828,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
)
s"$noun with unmergeable type parameters: $tname"
})
valueClauses
vparamSymss
}
val tpt = readTpt()(localCtx)
if (isMacro) {
Expand All @@ -838,7 +840,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
)
sym.addAnnotation(annot)
}
val valueParamss = normalizeIfConstructor(vparamss, isCtor)
val valueParamss = normalizeIfConstructor(sym.enclClass, vparamss, valueClauses, isCtor)
val resType = effectiveResultType(sym, tpt.tpe)
ctx.setInfo(sym, defn.DefDefType(if (isCtor) Nil else typeParams, valueParamss, resType))
}
Expand Down Expand Up @@ -891,7 +893,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
else defn.ExprType(tpt.tpe))
}

def initialize(localCtx: Context)(implicit ctx: Context): Unit = ctx.trace(traceCompletion(symAddr, sym)) {
def initialize(localCtx: Context)(implicit ctx: Context) = ctx.trace(traceCompletion(symAddr, sym)) {
sym.rawInfo match {
case repr: TastyRepr =>
tag match {
Expand All @@ -900,26 +902,30 @@ class TreeUnpickler[Tasty <: TastyUniverse](
case TYPEDEF | TYPEPARAM => TypeDef(repr, localCtx)
case PARAM => TermParam(repr, localCtx)
}
repr.tflags
case _ => // nothing to do here (assume correctly initalised)
ctx.log(s"${showSym(sym)} is already initialised, in owner ${showSym(sym.owner)}")
EmptyTastyFlags
}
}

try {
val localCtx = ctx.withOwner(sym)
if (sym.isClass) {
inIndexScopedStatsContext(localCtx0 => initialize(localCtx0)(ctx))(localCtx)
}
else {
initialize(localCtx)
val tflags = {
if (sym.isClass) {
inIndexScopedStatsContext(localCtx0 => initialize(localCtx0)(ctx))(localCtx)
}
else {
initialize(localCtx)
}
}
NoCycle(at = symAddr)
NoCycle(at = symAddr, tflags)
}
catch ctx.onCompletionError(sym)
finally goto(end)
}

private def traceCompletion(addr: Addr, sym: Symbol)(implicit ctx: Context) = TraceInfo[Unit](
private def traceCompletion(addr: Addr, sym: Symbol)(implicit ctx: Context) = TraceInfo[TastyFlagSet](
query = "begin completion",
qual = s"${showSym(sym)} in context ${showSym(ctx.owner)} $addr",
res = _ => s"completed ${showSym(sym)}: ${showType(sym.info)}"
Expand Down Expand Up @@ -1032,7 +1038,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
unsupportedTermTreeError("package statement")
case _ =>
skipTree() // readTerm()(ctx.withOwner(exprOwner))
NoCycle(at = NoAddr)
NoCycle(at = NoAddr, tflags = EmptyTastyFlags)
}

def readIndexedStatsAsSyms(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[NoCycle] =
Expand Down Expand Up @@ -1331,8 +1337,8 @@ object TreeUnpickler {

sealed trait MaybeCycle
object MaybeCycle {
case class NoCycle(at: Addr) extends MaybeCycle
case object Tombstone extends MaybeCycle
case class NoCycle(at: Addr, tflags: TastyFlagSet) extends MaybeCycle
case object Tombstone extends MaybeCycle
}

/** An enumeration indicating which subtrees should be added to an OwnerTree. */
Expand Down
66 changes: 49 additions & 17 deletions src/compiler/scala/tools/nsc/tasty/bridge/AnnotationOps.scala
Expand Up @@ -18,33 +18,65 @@ import scala.tools.nsc.tasty.TastyUniverse
trait AnnotationOps { self: TastyUniverse =>
import self.{symbolTable => u}

private[bridge] final def mkAnnotation(tree: Tree): u.Annotation = tree match {
case u.Apply(u.Select(u.New(tpt), u.nme.CONSTRUCTOR), args) =>
u.AnnotationInfo(tpt.tpe, args, Nil)
case u.Apply(u.TypeApply(u.Select(u.New(tpt), u.nme.CONSTRUCTOR), tpargs), args) =>
u.AnnotationInfo(u.appliedType(tpt.tpe, tpargs.map(_.tpe)), args, Nil)
case u.New(tpt) =>
// this is to handle incorrectly formatted annotations in dotty - https://github.com/lampepfl/dotty/issues/10113
u.AnnotationInfo(tpt.tpe, Nil, Nil)
case _ =>
throw new Exception(s"unexpected annotation kind from TASTy: ${u.showRaw(tree)}")
trait ShowKind[T] {
def showKind(annot: String, t: T)(implicit ctx: Context): String
}

sealed abstract class DeferredAnnotation {
object ShowKind {
implicit object ShowSymbol extends ShowKind[u.Symbol] {
def showKind(annot: String, t: u.Symbol)(implicit ctx: Context): String = s"$annot ${location(t)}"
}
implicit object ShowType extends ShowKind[u.Type] {
def showKind(annot: String, t: u.Type)(implicit ctx: Context): String =
s"type ${showType(t, wrap = false)} $annot of ${location(ctx.owner)}"
}
}

private[bridge] final def mkAnnotation[T: ShowKind](tree: Tree, annotee: T)(implicit ctx: Context): u.Annotation = {
def go(tpargs: List[Type], args: List[List[Tree]], tree: Tree): u.Annotation = tree match {
case u.Select(u.New(tpt), u.nme.CONSTRUCTOR) =>
val atp = if (tpargs.isEmpty) tpt.tpe else u.appliedType(tpt.tpe, tpargs)
if (args.lengthIs > 1) {
val soFar = s"@${atp.typeSymbol.name.toString}${args.map(_.mkString("(", ", ", ")")).mkString("")}"
u.reporter.warning(u.NoPosition,
"Implementation limitation: multiple argument lists on annotations are\n"+
"currently not supported; ignoring arguments " + args(1) + " on\n"+
s"${implicitly[ShowKind[T]].showKind(soFar, annotee)}")
}
u.AnnotationInfo(atp, args.headOption.getOrElse(Nil), Nil)
case u.TypeApply(pre, newTpArgs) if tpargs.isEmpty =>
go(newTpArgs.map(_.tpe), args, pre)
case u.Apply(pre, Nil) => // skip the empty term param list
go(tpargs, args, pre)
case u.Apply(pre, newArgs) =>
go(tpargs, newArgs :: args, pre)
case _ =>
throw new Exception(s"unexpected annotation kind from TASTy: ${u.showRaw(tree)}")
}
tree match {
case u.New(tpt) =>
// this is to handle incorrectly formatted annotations in dotty - https://github.com/lampepfl/dotty/issues/10113
u.AnnotationInfo(tpt.tpe, Nil, Nil)
case _ =>
go(Nil, Nil, tree)
}
}

sealed abstract class DeferredAnnotation(annotSym: Symbol) {

private[bridge] def eager(annotee: Symbol)(implicit ctx: Context): u.AnnotationInfo
protected def eager(annotee: Symbol)(implicit ctx: Context): u.AnnotationInfo
private[bridge] final def lzy(annotee: Symbol)(implicit ctx: Context): u.LazyAnnotationInfo = {
u.AnnotationInfo.lazily(eager(annotee))
u.AnnotationInfo.lazily(annotSym, eager(annotee))
}
}

object DeferredAnnotation {

def fromTree(tree: Symbol => Context => Tree): DeferredAnnotation = {
new DeferredAnnotation {
private[bridge] final def eager(annotee: Symbol)(implicit ctx: Context): u.AnnotationInfo = {
def fromTree(annotSym: Symbol)(tree: Symbol => Context => Tree): DeferredAnnotation = {
new DeferredAnnotation(annotSym) {
protected final def eager(annotee: Symbol)(implicit ctx: Context): u.AnnotationInfo = {
val atree = tree(annotee)(ctx)
mkAnnotation(atree)
mkAnnotation(atree, annotee)
}
}
}
Expand Down
25 changes: 13 additions & 12 deletions src/compiler/scala/tools/nsc/tasty/bridge/ContextOps.scala
Expand Up @@ -96,27 +96,28 @@ trait ContextOps { self: TastyUniverse =>

/**Perform an operation within a context that has the mode `IndexStats` will force any collected annotations
* afterwards */
def inIndexStatsContext(op: Context => Unit)(implicit ctx: Context): Unit = {
def inIndexStatsContext[T](op: Context => T)(implicit ctx: Context): T = {
val statsCtx = ctx.addMode(IndexStats)
op(statsCtx)
statsCtx.initialContext.forceAnnotations()
try op(statsCtx)
finally statsCtx.initialContext.forceAnnotations()
}

/** Perform an operation within a context that has the mode `InnerScope` will enter any inline methods afterwards */
def inInnerScopeContext(op: Context => Unit)(implicit ctx: Context): Unit = {
def inInnerScopeContext[T](op: Context => T)(implicit ctx: Context): T = {
val innerCtx = ctx.addMode(InnerScope)
op(innerCtx)
innerCtx.initialContext.enterLatentDefs(innerCtx.owner)
try op(innerCtx)
finally innerCtx.initialContext.enterLatentDefs(innerCtx.owner)
}


/** an aggregate of `inInnerScopeContext` within `inIndexStatsContext` */
def inIndexScopedStatsContext(op: Context => Unit)(implicit ctx: Context): Unit = {
def inIndexScopedStatsContext[T](op: Context => T)(implicit ctx: Context): T = {
inIndexStatsContext(inInnerScopeContext(op)(_))(ctx)
}

/**Forces lazy annotations, if one is `scala.annotation.internal.Child` then it will add the referenced type as a
* sealed child.
/**Analyses critical annotations, critical annotations will be forced as they are necessary to
* the reading of TASTy. E.g. `scala.annotation.internal.Child` is a critical annotation that
* must be forced to add its first type argument as a sealed child.
*/
private def analyseAnnotations(sym: Symbol)(implicit ctx: Context): Unit = {

Expand All @@ -137,8 +138,7 @@ trait ContextOps { self: TastyUniverse =>
var problematic: List[String] = Nil

for (annot <- sym.annotations) {
annot.completeInfo()
if (annot.tpe.typeSymbolDirect === defn.ChildAnnot) {
if (annot.symbol === defn.ChildAnnot) {
val child = {
val child0 = lookupChild(annot.tpe.typeArgs.head)
if (child0 eq sym) {
Expand All @@ -161,6 +161,7 @@ trait ContextOps { self: TastyUniverse =>
if ((annot.symbol eq defn.TargetNameAnnotationClass) ||
(annot.symbol eq defn.StaticMethodAnnotationClass)) {
problematic ::= inOwner { implicit ctx =>
annot.completeInfo() // these should be safe to force
unsupportedMessage(s"annotation on $sym: @$annot")
}
}
Expand Down Expand Up @@ -196,7 +197,7 @@ trait ContextOps { self: TastyUniverse =>
}
else {
log(s"eagerly adding annotations to ${showSym(sym)}")
analyseAnnotations(sym.setAnnotations(annots.map(_.eager(sym))))
analyseAnnotations(sym.setAnnotations(annots.map(_.lzy(sym))))
}
}
}
Expand Down
21 changes: 15 additions & 6 deletions src/compiler/scala/tools/nsc/tasty/bridge/SymbolOps.scala
Expand Up @@ -17,6 +17,8 @@ import scala.tools.nsc.tasty.{SafeEq, TastyUniverse, ForceKinds, TastyModes}, Ta
import scala.tools.tasty.{TastyName, Signature, TastyFlags}, TastyName.SignedName, Signature.MethodSignature, TastyFlags._
import scala.tools.tasty.ErasedTypeRef

import scala.tools.nsc.tasty.TreeUnpickler.MaybeCycle.NoCycle

/**This layer deals with selecting a member symbol from a type using a `TastyName`,
* also contains factories for making type references to symbols.
*/
Expand Down Expand Up @@ -121,12 +123,19 @@ trait SymbolOps { self: TastyUniverse =>
def symIsExperimental(sym: Symbol) = sym.hasAnnotation(defn.ExperimentalAnnotationClass)

/** if isConstructor, make sure it has one non-implicit parameter list */
def normalizeIfConstructor(termParamss: List[List[Symbol]], isConstructor: Boolean): List[List[Symbol]] =
if (isConstructor &&
(termParamss.isEmpty || termParamss.head.nonEmpty && termParamss.head.head.isImplicit))
Nil :: termParamss
else
termParamss
def normalizeIfConstructor(owner: Symbol, termParamss: List[List[Symbol]], paramClauses: List[List[NoCycle]], isConstructor: Boolean): List[List[Symbol]] =
if (!isConstructor) termParamss
else {
paramClauses match {
case (vparam :: _) :: _ if vparam.tflags.is(Implicit, butNot=Given) => Nil :: termParamss
case _ =>
if (paramClauses.forall(paramClause => paramClause.nonEmpty && paramClause.head.tflags.is(Given))) {
termParamss :+ Nil
} else {
termParamss
}
}
}

private[bridge] def lookupSymbol(space: Type, tname: TastyName)(implicit ctx: Context): Symbol = {
deepComplete(space)
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/tasty/bridge/TreeOps.scala
Expand Up @@ -166,7 +166,7 @@ trait TreeOps { self: TastyUniverse =>
}
}

def Annotated(tpt: Tree, annot: Tree): Tree = {
def Annotated(tpt: Tree, annot: Tree)(implicit ctx: Context): Tree = {
if (annot.tpe.typeSymbol === defn.RepeatedAnnot
&& tpt.tpe.typeSymbol.isSubClass(u.definitions.SeqClass)
&& tpt.tpe.typeArgs.length == 1) {
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/scala/tools/nsc/tasty/bridge/TypeOps.scala
Expand Up @@ -223,9 +223,9 @@ trait TypeOps { self: TastyUniverse =>
def IntersectionType(tps: Type*): Type = u.intersectionType(tps.toList)
def IntersectionType(tps: List[Type]): Type = u.intersectionType(tps)

def AnnotatedType(tpe: Type, annot: Tree): Type = tpe match {
case u.AnnotatedType(annots, tpe) => u.AnnotatedType(annots :+ mkAnnotation(annot), tpe)
case _ => u.AnnotatedType(mkAnnotation(annot) :: Nil , tpe)
def AnnotatedType(tpe: Type, annot: Tree)(implicit ctx: Context): Type = tpe match {
case u.AnnotatedType(annots, tpe) => u.AnnotatedType(annots :+ mkAnnotation(annot, tpe), tpe)
case _ => u.AnnotatedType(mkAnnotation(annot, tpe) :: Nil , tpe)
}

def SuperType(thisTpe: Type, superTpe: Type): Type = u.SuperType(thisTpe, superTpe)
Expand Down
8 changes: 5 additions & 3 deletions src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
Expand Up @@ -889,7 +889,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
if (ms.nonEmpty && clazz.isTrait && clazz.isInterface)
clazz.resetFlag(INTERFACE)

if (normalizedMember.isMethod) {
if (normalizedMember.isMethod && !normalizedMember.isScala3Defined) {
val newTpe = subst(outerEnv, normalizedMember.info)
// only do it when necessary, otherwise the method type might be at a later phase already
if (newTpe != normalizedMember.info) {
Expand Down Expand Up @@ -930,7 +930,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
private def normalizeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv): List[Symbol] = {
sym :: (
if (!sym.isMethod || enteringTyper(sym.typeParams.isEmpty)) Nil
if (!sym.isMethod || sym.isScala3Defined || enteringTyper(sym.typeParams.isEmpty)) Nil
else if (sym.hasDefault) {
/* Specializing default getters is useless, also see scala/bug#7329 . */
sym.resetFlag(SPECIALIZED)
Expand Down Expand Up @@ -1024,7 +1024,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
specMember
}

if (!sym.isMethod || sym.isConstructor || hasUnspecializableAnnotation(sym) || sym.isSuperAccessor) {
if (!sym.isMethod || sym.isConstructor || hasUnspecializableAnnotation(sym) || sym.isSuperAccessor
|| sym.isScala3Defined) { // Scala 3 does not have specialised methods yet.
// ) {
Nil
} else {
val stvars = specializedTypeVars(sym)
Expand Down

0 comments on commit aa579da

Please sign in to comment.