Skip to content

Commit

Permalink
update dotty, re-enable tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bishabosha committed Feb 16, 2021
1 parent 7927353 commit 5250f6f
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 131 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.0.0-M4-bin-20210214-80befc3-NIGHTLY" // TASTy version 28.0.1
val supportedTASTyRelease = "3.0.0-M4-bin-20210215-53a2dc5-NIGHTLY" // TASTy version 28.0.1
val scala3Compiler = "org.scala-lang" % "scala3-compiler_3.0.0-M4" % supportedTASTyRelease
}

Expand Down
230 changes: 122 additions & 108 deletions src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala
Expand Up @@ -686,38 +686,26 @@ class TreeUnpickler[Tasty <: TastyUniverse](
case _ =>
val start = currentAddr
cycleAtAddr(start) = Tombstone
val noCycle = readNewMember()
val noCycle = initializeMember()
cycleAtAddr.remove(start)
noCycle
}

private def readNewMember()(implicit ctx: Context): NoCycle = {
val symAddr = currentAddr
val tag = readByte()
val end = readEnd()
val tname = readTastyName()
val sym = symAtAddr(symAddr)
val repr = sym.repr
private def initializeMember()(implicit ctx: Context): NoCycle = {
val symAddr = currentAddr
val tag = readByte()
val end = readEnd()
val tname = readTastyName()
val sym = symAtAddr(symAddr)

ctx.log(s"$symAddr completing ${showSym(sym)} in scope ${showSym(ctx.owner)}")

def readParamss(skipTypeParams: Boolean)(implicit ctx: Context): List[List[NoCycle]] = {
def readParamss()(implicit ctx: Context): List[List[NoCycle]] = {
def readRest() = {
if (nextByte == SPLITCLAUSE) readByte()
readParamss(skipTypeParams)
}

def emptyTypeParams() = {
while (nextByte === TYPEPARAM) skipTree()
Nil
readParamss()
}

nextByte match {
case PARAM => readParams[NoCycle](PARAM) :: readRest()
case TYPEPARAM =>
val typarams =
if (skipTypeParams) emptyTypeParams() else readParams[NoCycle](TYPEPARAM)
typarams :: readRest()
case TYPEPARAM => readParams[NoCycle](TYPEPARAM) :: readRest()
case EMPTYCLAUSE => readByte(); Nil :: readRest()
case _ => Nil
}
Expand All @@ -727,97 +715,123 @@ class TreeUnpickler[Tasty <: TastyUniverse](
unsupportedWhen(unsupported.hasFlags, s"${showTasty(unsupported)} ${sym.kindString} $tname")
}

try {
val localCtx = ctx.withOwner(sym)
tag match {
case DEFDEF =>
val isMacro = repr.originalFlagSet.is(Erased | Macro)
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (Extension | Exported | Infix | optFlag(isMacro)(Erased)))
val isCtor = sym.isConstructor
val paramDefss = readParamss(skipTypeParams=isCtor)(localCtx)
val typeParams: List[Symbol] = {
if (isCtor) {
sym.owner.typeParams
}
else {
val first = paramDefss.take(1).flatten.map(symFromNoCycle)
if (first.headOption.exists(_.isType)) first else Nil
}
}
val vparamss: List[List[NoCycle]] = {
val valueClauses = paramDefss.drop(if (typeParams.isEmpty) 0 else 1)
val hasTypeParams = valueClauses.exists(_.exists(nc => symFromNoCycle(nc).isType))
unsupportedWhen(hasTypeParams, s"extension method with secondary type parameter list: $tname")
valueClauses
}
val tpt = readTpt()(localCtx)
if (isMacro) {
val impl = tpd.Macro(readTerm()(ctx.addMode(ReadMacro)))
val annot = symbolTable.AnnotationInfo(
atp = symbolTable.definitions.MacroImplLocationAnnotation.tpe,
args = List(impl),
assocs = Nil
)
sym.addAnnotation(annot)
}
val valueParamss = normalizeIfConstructor(vparamss.map(_.map(symFromNoCycle)), isCtor)
val resType = effectiveResultType(sym, typeParams, tpt.tpe)
ctx.setInfo(sym, defn.DefDefType(if (isCtor) Nil else typeParams, valueParamss, resType))
case VALDEF => // valdef in TASTy is either a singleton object or a method forwarder to a local value.
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (Enum | Extension | Exported))
val tpe = readTpt()(localCtx).tpe
ctx.setInfo(sym,
if (repr.originalFlagSet.is(SingletonEnumFlags)) {
val enumClass = sym.objectImplementation
val selfTpe = defn.SingleType(sym.owner.thisPrefix, sym)
val ctor = ctx.unsafeNewSymbol(
owner = enumClass,
name = TastyName.Constructor,
flags = Method,
info = defn.DefDefType(Nil, Nil :: Nil, selfTpe)
)
enumClass.typeOfThis = selfTpe
ctx.setInfo(enumClass, defn.ClassInfoType(intersectionParts(tpe), ctor :: Nil, enumClass))
prefixedRef(sym.owner.thisPrefix, enumClass)
}
else if (sym.isFinal && isConstantType(tpe)) defn.InlineExprType(tpe)
else if (sym.isMethod) defn.ExprType(tpe)
else tpe
def DefDef(repr: TastyRepr, localCtx: Context)(implicit ctx: Context): Unit = {
val isMacro = repr.originalFlagSet.is(Erased | Macro)
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (Extension | Exported | Infix | optFlag(isMacro)(Erased)))
val isCtor = sym.isConstructor
val paramDefss = readParamss()(localCtx).map(_.map(symFromNoCycle))
val typeParams = {
// 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 vparamss = {
// 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))
unsupportedWhen(hasTypeParams, {
val noun = (
if (isCtor) "constructor"
else if (repr.tastyOnlyFlags.is(Extension)) "extension method"
else "method"
)
case TYPEDEF | TYPEPARAM =>
val allowedShared = Enum | Opaque | Infix
val allowedTypeFlags = allowedShared | Exported
val allowedClassFlags = allowedShared | Open | Transparent
if (sym.isClass) {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ allowedClassFlags)
sym.owner.ensureCompleted()
readTemplate()(localCtx)
}
else {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ allowedTypeFlags)
val rhs = readTpt()(if (repr.originalFlagSet.is(Opaque)) localCtx.addMode(OpaqueTypeDef) else localCtx)
val info =
if (repr.originalFlagSet.is(Opaque)) {
val (info, alias) = defn.OpaqueTypeToBounds(rhs.tpe)
ctx.markAsOpaqueType(sym, alias)
info
}
else rhs.tpe
ctx.setInfo(sym, defn.NormalisedBounds(info, sym))
if (sym.is(Param)) sym.reset(Private | Protected)
// sym.resetFlag(Provisional)
s"$noun with unmergeable type parameters: $tname"
})
valueClauses
}
val tpt = readTpt()(localCtx)
if (isMacro) {
val impl = tpd.Macro(readTerm()(ctx.addMode(ReadMacro)))
val annot = symbolTable.AnnotationInfo(
atp = symbolTable.definitions.MacroImplLocationAnnotation.tpe,
args = List(impl),
assocs = Nil
)
sym.addAnnotation(annot)
}
val valueParamss = normalizeIfConstructor(vparamss, isCtor)
val resType = effectiveResultType(sym, typeParams, tpt.tpe)
ctx.setInfo(sym, defn.DefDefType(if (isCtor) Nil else typeParams, valueParamss, resType))
}

def ValDef(repr: TastyRepr, localCtx: Context)(implicit ctx: Context): Unit = {
// valdef in TASTy is either a singleton object or a method forwarder to a local value.
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (Enum | Extension | Exported))
val tpe = readTpt()(localCtx).tpe
ctx.setInfo(sym,
if (repr.originalFlagSet.is(SingletonEnumFlags)) {
val enumClass = sym.objectImplementation
val selfTpe = defn.SingleType(sym.owner.thisPrefix, sym)
val ctor = ctx.unsafeNewSymbol(
owner = enumClass,
name = TastyName.Constructor,
flags = Method,
info = defn.DefDefType(Nil, Nil :: Nil, selfTpe)
)
enumClass.typeOfThis = selfTpe
ctx.setInfo(enumClass, defn.ClassInfoType(intersectionParts(tpe), ctor :: Nil, enumClass))
prefixedRef(sym.owner.thisPrefix, enumClass)
}
else if (sym.isFinal && isConstantType(tpe)) defn.InlineExprType(tpe)
else if (sym.isMethod) defn.ExprType(tpe)
else tpe
)
}

def TypeDef(repr: TastyRepr, localCtx: Context)(implicit ctx: Context): Unit = {
val allowedShared = Enum | Opaque | Infix
val allowedTypeFlags = allowedShared | Exported
val allowedClassFlags = allowedShared | Open | Transparent
if (sym.isClass) {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ allowedClassFlags)
sym.owner.ensureCompleted()
readTemplate()(localCtx)
}
else {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ allowedTypeFlags)
val rhs = readTpt()(if (repr.originalFlagSet.is(Opaque)) localCtx.addMode(OpaqueTypeDef) else localCtx)
val info =
if (repr.originalFlagSet.is(Opaque)) {
val (info, alias) = defn.OpaqueTypeToBounds(rhs.tpe)
ctx.markAsOpaqueType(sym, alias)
info
}
case PARAM =>
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (ParamAlias | Exported))
val tpt = readTpt()(localCtx)
ctx.setInfo(sym,
if (nothingButMods(end) && sym.not(ParamSetter)) tpt.tpe
else defn.ExprType(tpt.tpe))
else rhs.tpe
ctx.setInfo(sym, defn.NormalisedBounds(info, sym))
if (sym.is(Param)) sym.reset(Private | Protected)
}
}

def TermParam(repr: TastyRepr, localCtx: Context)(implicit ctx: Context): Unit = {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (ParamAlias | Exported))
val tpt = readTpt()(localCtx)
ctx.setInfo(sym,
if (nothingButMods(end) && sym.not(ParamSetter)) tpt.tpe
else defn.ExprType(tpt.tpe))
}

def initialize()(implicit ctx: Context): Unit = {
val repr = sym.rawInfo match {
case repr: TastyRepr => repr
case _ => return () // nothing to do here (assume correctly initalised)
}
ctx.log(s"$symAddr completing ${showSym(sym)} in scope ${showSym(ctx.owner)}")
val localCtx = ctx.withOwner(sym)
tag match {
case DEFDEF => DefDef(repr, localCtx)
case VALDEF => ValDef(repr, localCtx)
case TYPEDEF | TYPEPARAM => TypeDef(repr, localCtx)
case PARAM => TermParam(repr, localCtx)
}
}

try {
initialize()
ctx.log(s"$symAddr @@@ ${showSym(sym)}.tpe =:= '[${if (sym.isType) sym.tpe else sym.info}]; owned by ${location(sym.owner)}")
goto(end)
NoCycle(at = symAddr)
} catch ctx.onCompletionError(sym)
}
catch ctx.onCompletionError(sym)
finally goto(end)
}

private def readTemplate()(implicit ctx: Context): Unit = {
Expand Down
27 changes: 14 additions & 13 deletions src/compiler/scala/tools/nsc/tasty/bridge/SymbolOps.scala
Expand Up @@ -46,30 +46,31 @@ trait SymbolOps { self: TastyUniverse =>

implicit final class SymbolDecorator(val sym: Symbol) {

def isScala3Macro(implicit ctx: Context): Boolean = repr.originalFlagSet.is(Inline | Macro)
def isScala3Inline(implicit ctx: Context): Boolean = repr.originalFlagSet.is(Inline)
def isScala2Macro(implicit ctx: Context): Boolean = repr.originalFlagSet.is(Erased | Macro)
def isScala3Macro: Boolean = repr.originalFlagSet.is(Inline | Macro)
def isScala3Inline: Boolean = repr.originalFlagSet.is(Inline)
def isScala2Macro: Boolean = repr.originalFlagSet.is(Erased | Macro)

def isPureMixinCtor(implicit ctx: Context): Boolean = isMixinCtor && repr.originalFlagSet.is(Stable)
def isPureMixinCtor: Boolean = isMixinCtor && repr.originalFlagSet.is(Stable)
def isMixinCtor: Boolean = u.nme.MIXIN_CONSTRUCTOR == sym.name && sym.owner.isTrait

def isTraitParamAccessor(implicit ctx: Context): Boolean = sym.owner.isTrait && repr.originalFlagSet.is(FieldAccessor|ParamSetter)
def isTraitParamAccessor: Boolean = sym.owner.isTrait && repr.originalFlagSet.is(FieldAccessor|ParamSetter)

def isParamGetter(implicit ctx: Context): Boolean =
def isParamGetter: Boolean =
sym.isMethod && sym.repr.originalFlagSet.is(FlagSets.FieldAccessorFlags)

/** A computed property that should only be called on a symbol which is known to have been initialised by the
* Tasty Unpickler and is not yet completed.
*
* @todo adapt callsites and type so that this property is more safe to call (barring mutation from uncontrolled code)
*/
def repr(implicit ctx: Context): TastyRepr = {
require(sym.rawInfo.isInstanceOf[TastyRepr], {
val raw = u.showRaw(sym.rawInfo)
val tastyRepr = u.typeOf[TastyRepr]
s"${showSym(sym)} is already completed. Expected $tastyRepr, is $raw. in ${ctx.source}"
})
sym.rawInfo.asInstanceOf[TastyRepr]
def repr: TastyRepr = {
try sym.rawInfo.asInstanceOf[TastyRepr]
catch {
case err: ClassCastException =>
val raw = u.showRaw(sym.rawInfo)
val tastyRepr = u.typeOf[TastyRepr]
throw new AssertionError(s"$sym is already completed. Expected $tastyRepr, is $raw.")
}
}

def ensureCompleted(): Unit = {
Expand Down
2 changes: 1 addition & 1 deletion test/tasty/neg/src-2/TestDependentExtension.check
@@ -1,4 +1,4 @@
TestDependentExtension_fail.scala:11: error: Unsupported Scala 3 extension method with secondary type parameter list: extract; found in trait tastytest.DependentExtension.
TestDependentExtension_fail.scala:11: error: Unsupported Scala 3 extension method with unmergeable type parameters: extract; found in trait tastytest.DependentExtension.
val res = implicitly[DependentExtension].extract(box)(_ + 1)
^
1 error
2 changes: 1 addition & 1 deletion test/tasty/neg/src-2/TestRealFunctor.check
@@ -1,4 +1,4 @@
TestRealFunctor_fail.scala:6: error: Unsupported Scala 3 extension method with secondary type parameter list: map; found in trait tastytest.RealFunctor.
TestRealFunctor_fail.scala:6: error: Unsupported Scala 3 extension method with unmergeable type parameters: map; found in trait tastytest.RealFunctor.
def map[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f)
^
1 error
4 changes: 2 additions & 2 deletions test/tasty/run/src-2/tastytest/TestMacroCompat.scala
Expand Up @@ -8,7 +8,7 @@ object TestMacroCompat extends Suite("TestMacroCompat") {

test(assert(testCase(15) === ("15", Position("TestMacroCompat.scala", 9))))
test(assert(constInt("") === 1))
// test(assert(mono === 1))
// test(assert(poly[String] === "String"))
test(assert(mono === 1))
test(assert(poly[String] === "String"))

}
8 changes: 4 additions & 4 deletions test/tasty/run/src-3/tastytest/MacroCompat.scala
Expand Up @@ -11,11 +11,11 @@ object MacroCompat {
inline def constInt[T](x: T): Int = ${ Macros3.constIntImpl[T]('x) }

object Bundles {
// def mono: Int = macro MacroImpl.mono
// inline def mono: Int = ${ Macros3.monoImpl }
def mono: Int = macro MacroImpl.mono
inline def mono: Int = ${ Macros3.monoImpl }

// def poly[T]: String = macro MacroImpl.poly[T]
// inline def poly[T]: String = ${ Macros3.polyImpl[T] }
def poly[T]: String = macro MacroImpl.poly[T]
inline def poly[T]: String = ${ Macros3.polyImpl[T] }
}

def testCase(test: => Any)(implicit pos: Position): (String, Position) =
Expand Down
2 changes: 1 addition & 1 deletion test/tasty/test/scala/tools/tastytest/TastyTestJUnit.scala
Expand Up @@ -76,7 +76,7 @@ import scala.reflect.runtime.ReflectionUtils
object TastyTestJUnit {
final implicit class TryOps(val op: Try[Unit]) extends AnyVal {
def eval: Unit = op match {
case Failure(err) => throw ReflectionUtils.unwrapThrowable(err)//fail(ReflectionUtils.unwrapThrowable(err).toString)
case Failure(err) => fail(err.toString)
case _ => ()
}
}
Expand Down

0 comments on commit 5250f6f

Please sign in to comment.