Skip to content

Commit

Permalink
handle invisible flag
Browse files Browse the repository at this point in the history
also document constructor
type params
  • Loading branch information
bishabosha committed May 7, 2021
1 parent 1892706 commit 20ae390
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 47 deletions.
81 changes: 53 additions & 28 deletions src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala
Expand Up @@ -69,8 +69,12 @@ class TreeUnpickler[Tasty <: TastyUniverse](

//---------------- unpickling trees ----------------------------------------------------------------------------------

private def registerSym(addr: Addr, sym: Symbol)(implicit ctx: Context) = {
ctx.log(s"$addr registered ${showSym(sym)} in ${location(sym.owner)}")
private def registerSym(addr: Addr, sym: Symbol, rejected: Boolean)(implicit ctx: Context) = {
assert(!(rejected && isSymbol(sym)), "expected no symbol when rejected")
ctx.log(
if (isSymbol(sym)) s"$addr registered ${showSym(sym)} in ${location(sym.owner)}"
else s"$addr registering symbol was rejected"
)
symAtAddr(addr) = sym
}

Expand Down Expand Up @@ -464,7 +468,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
createMemberSymbol()
case TEMPLATE =>
val localDummy = ctx.newLocalDummy
registerSym(currentAddr, localDummy)
registerSym(currentAddr, localDummy, rejected = false)
localDummy
case tag =>
assert(tag != BIND, "bind pattern symbol creation from TASTy")
Expand All @@ -475,12 +479,23 @@ class TreeUnpickler[Tasty <: TastyUniverse](
* @return the created symbol
*/
def createMemberSymbol()(implicit ctx: Context): Symbol = {

def rejectSymbol(owner: Symbol, name: TastyName, flags: TastyFlagSet): Boolean = {
def isPureMixinCtor =
name == TastyName.MixinConstructor && owner.isTrait && flags.is(Stable)
def isInvisible =
flags.is(Invisible)

isPureMixinCtor || isInvisible
}

val start = currentAddr
val tag = readByte()
def isTypeTag = tag === TYPEDEF || tag === TYPEPARAM
val end = readEnd()
val parsedName: TastyName = readTastyName()
ctx.log(s"$start ::: => create ${astTagToString(tag)} ${parsedName.debug}")
def debugSymCreate: String = s"${astTagToString(tag)} ${parsedName.debug}"
ctx.log(s"$start ::: => create $debugSymCreate")
skipParams()
val ttag = nextUnsharedTag
val isAbsType = isAbstractType(ttag)
Expand All @@ -489,13 +504,11 @@ class TreeUnpickler[Tasty <: TastyUniverse](
skipTree() // tpt
val rhsIsEmpty = nothingButMods(end)
if (!rhsIsEmpty) skipTree()
val (name, flags, annotations, privateWithin) = {
val (parsedFlags, annotations, privateWithin) =
readModifiers(end, readTypedAnnot, readTypedWithin, noSymbol)
val name = normalizeName(isTypeTag, parsedName)
val flags = addInferredFlags(tag, parsedFlags, name, isAbsType, isClass, rhsIsEmpty)
(name, flags, annotations, privateWithin)
}
val (parsedFlags0, annotations, privateWithin) =
readModifiers(end, readTypedAnnot, readTypedWithin, noSymbol)
val name = normalizeName(isTypeTag, parsedName)
val flags = addInferredFlags(tag, parsedFlags0, name, isAbsType, isClass, rhsIsEmpty)
def mkCompleter = new Completer(isClass, subReader(start, end), flags)(ctx.retractMode(IndexScopedStats))
def isTypeParameter = flags.is(Param) && isTypeTag
def canEnterInClass = !isTypeParameter
ctx.log {
Expand All @@ -509,34 +522,46 @@ class TreeUnpickler[Tasty <: TastyUniverse](
}
s"""$start parsed flags $debugFlags"""
}
val rejected = rejectSymbol(ctx.owner, name, flags)
val sym = {
if (tag === TYPEPARAM && ctx.owner.isConstructor) {
// TASTy encodes type parameters for constructors
// nsc only has class type parameters
ctx.findOuterClassTypeParameter(name.toTypeName)
}
else {
val completer = new Completer(isClass, subReader(start, end), flags)(ctx.retractMode(IndexScopedStats))
ctx.findRootSymbol(roots, name) match {
case Some(rootd) =>
ctx.redefineSymbol(rootd, flags, completer, privateWithin) // dotty "removes one completion" here from the flags, which is not possible in nsc
ctx.log(s"$start replaced info of ${showSym(rootd)}")
rootd
roots -= rootd
if (rejected) {
ctx.evict(rootd)
noSymbol
}
else {
ctx.redefineSymbol(rootd, flags, mkCompleter, privateWithin)
ctx.log(s"$start replaced info of ${showSym(rootd)}")
rootd
}
case _ =>
if (isClass) ctx.delayClassCompletion(ctx.owner, name.toTypeName, completer, privateWithin)
else ctx.delayCompletion(ctx.owner, name, completer, privateWithin)
if (rejected) noSymbol
else if (isClass) ctx.delayClassCompletion(ctx.owner, name.toTypeName, mkCompleter, privateWithin)
else ctx.delayCompletion(ctx.owner, name, mkCompleter, privateWithin)
}
}
}.ensuring(isSymbol(_), s"${ctx.classRoot}: Could not create symbol at $start")
if (tag == VALDEF && flags.is(FlagSets.SingletonEnum))
ctx.markAsEnumSingleton(sym)
registerSym(start, sym)
if (canEnterInClass && ctx.owner.isClass)
ctx.enterIfUnseen(sym)
if (isClass) {
val localCtx = ctx.withOwner(sym)
forkAt(templateStart).indexTemplateParams()(localCtx)
}
registerSym(start, sym, rejected)
if (isSymbol(sym)) {
if (tag == VALDEF && flags.is(FlagSets.SingletonEnum))
ctx.markAsEnumSingleton(sym)
if (canEnterInClass && ctx.owner.isClass)
ctx.enterIfUnseen(sym)
if (isClass) {
val localCtx = ctx.withOwner(sym)
forkAt(templateStart).indexTemplateParams()(localCtx)
}
ctx.adjustAnnotations(sym, annotations)
}
goto(start)
ctx.adjustAnnotations(sym, annotations)
sym
}

Expand Down Expand Up @@ -1026,7 +1051,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
tpd.SeqLiteral(until(end)(readTerm()), elemtpt)
case REFINEDtpt =>
val refineCls = symAtAddr.getOrElse(start, ctx.newRefinementClassSymbol)
registerSym(start, refineCls)
registerSym(start, refineCls, rejected = false)
typeAtAddr(start) = refineCls.ref
val parent = readTpt()
ctx.withOwner(refineCls).enterRefinement(parent.tpe) { refinedCtx =>
Expand Down
15 changes: 10 additions & 5 deletions src/compiler/scala/tools/nsc/tasty/bridge/ContextOps.scala
Expand Up @@ -59,7 +59,8 @@ trait ContextOps { self: TastyUniverse =>
}

final def location(owner: Symbol): String = {
if (owner.isClass) s"${owner.kindString} ${owner.fullNameString}"
if (!isSymbol(owner)) "<NoSymbol>"
else if (owner.isClass) s"${owner.kindString} ${owner.fullNameString}"
else s"${describeOwner(owner)} in ${location(owner.owner)}"
}

Expand Down Expand Up @@ -148,7 +149,6 @@ trait ContextOps { self: TastyUniverse =>
final def ignoreAnnotations: Boolean = u.settings.YtastyNoAnnotations

def requiresLatentEntry(decl: Symbol): Boolean = decl.isScala3Inline
def neverEntered(decl: Symbol): Boolean = decl.isPureMixinCtor

def canEnterOverload(decl: Symbol): Boolean = {
!(decl.isModule && isSymbol(findObject(thisCtx.owner, decl.name)))
Expand Down Expand Up @@ -285,11 +285,16 @@ trait ContextOps { self: TastyUniverse =>
}
}

def evict(sym: Symbol): Unit = {
sym.owner.rawInfo.decls.unlink(sym)
sym.info = u.NoType
}

final def enterIfUnseen(sym: Symbol): Unit = {
if (mode.is(IndexScopedStats))
initialContext.collectLatentEvidence(owner, sym)
val decl = declaringSymbolOf(sym)
if (!(requiresLatentEntry(decl) || neverEntered(decl)))
if (mode.is(IndexScopedStats))
initialContext.collectLatentEvidence(owner, decl)
if (!requiresLatentEntry(decl))
enterIfUnseen0(owner.rawInfo.decls, decl)
}

Expand Down
15 changes: 9 additions & 6 deletions src/compiler/scala/tools/nsc/tasty/bridge/FlagOps.scala
Expand Up @@ -16,8 +16,8 @@ import scala.tools.tasty.TastyFlags._
import scala.tools.nsc.tasty.TastyUniverse
import scala.reflect.internal.{Flags, ModifierFlags}

/**Handles encoding of `TastyFlagSet` to `scala.reflect` flags and witnessing which flags do not map directly
* from TASTy.
/** Handles encoding of `TastyFlagSet` to `scala.reflect` flags and witnessing which flags do not map directly
* from TASTy.
*/
trait FlagOps { self: TastyUniverse =>
import self.{symbolTable => u}
Expand All @@ -26,7 +26,7 @@ trait FlagOps { self: TastyUniverse =>

val TastyOnlyFlags: TastyFlagSet = (
Erased | Internal | Inline | InlineProxy | Opaque | Extension | Given | Exported | Transparent
| Enum | Infix | Open | ParamAlias | Invisible
| Enum | Infix | Open | ParamAlias | Invisible
)

object Creation {
Expand All @@ -52,14 +52,17 @@ trait FlagOps { self: TastyUniverse =>
implicit final class SymbolFlagOps(val sym: Symbol) {
def reset(tflags: TastyFlagSet)(implicit ctx: Context): sym.type =
ctx.resetFlag0(sym, unsafeEncodeTastyFlagSet(tflags))
def isOneOf(mask: TastyFlagSet): Boolean = sym.hasFlag(unsafeEncodeTastyFlagSet(mask))
def is(mask: TastyFlagSet): Boolean = sym.hasAllFlags(unsafeEncodeTastyFlagSet(mask))
def isOneOf(mask: TastyFlagSet): Boolean =
sym.hasFlag(unsafeEncodeTastyFlagSet(mask))
def is(mask: TastyFlagSet): Boolean =
sym.hasAllFlags(unsafeEncodeTastyFlagSet(mask))
def is(mask: TastyFlagSet, butNot: TastyFlagSet): Boolean =
if (!butNot)
sym.is(mask)
else
sym.is(mask) && sym.not(butNot)
def not(mask: TastyFlagSet): Boolean = sym.hasNoFlags(unsafeEncodeTastyFlagSet(mask))
def not(mask: TastyFlagSet): Boolean =
sym.hasNoFlags(unsafeEncodeTastyFlagSet(mask))
}

/** encodes a `TastyFlagSet` as a `symbolTable.FlagSet`, the flags in `FlagSets.TastyOnlyFlags` are ignored.
Expand Down
14 changes: 6 additions & 8 deletions src/compiler/scala/tools/nsc/tasty/bridge/SymbolOps.scala
Expand Up @@ -49,10 +49,6 @@ trait SymbolOps { self: TastyUniverse =>

def isScala3Inline: Boolean = repr.originalFlagSet.is(Inline)
def isScala2Macro: Boolean = repr.originalFlagSet.is(FlagSets.Scala2Macro)

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

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

def isParamGetter: Boolean =
Expand Down Expand Up @@ -176,10 +172,12 @@ trait SymbolOps { self: TastyUniverse =>
val paramSyms = meth0.paramss.flatten
val resTpe = meth0.finalResultType
val sameParamSize = paramSyms.length === paramRefs.length
def sameTyParamSize = tyParamCount === (
if (qual === TastyName.Constructor) member.owner.typeParams.length
else sym.typeParams.length
)
def sameTyParamSize = tyParamCount === ({
// the signature of a class/mixin constructor includes
// type parameters, in nsc these come from the parent.
val tyParamOwner = if (qual.isConstructorName) member.owner else sym
tyParamOwner.typeParams.length
})
def sameParams = paramSyms.lazyZip(paramRefs).forall({
case (paramSym, paramRef) => sameErasure(sym)(paramSym.tpe, paramRef)
})
Expand Down
13 changes: 13 additions & 0 deletions test/tasty/neg/src-2/TestInvisibleDefs.check
@@ -0,0 +1,13 @@
TestInvisibleDefs_fail.scala:5: error: type argIsHello is not a member of package tastytest
def foo: tastytest.argIsHello = ??? // has invisible flag so should not be seen
^
TestInvisibleDefs_fail.scala:6: error: type argIsHello is not a member of package tastytest
def bar: tastytest.argIsHello = ??? // second try on same type
^
TestInvisibleDefs_fail.scala:11: error: value getStatus is not a member of tastytest.InvisibleDefs.MyBean
mybean.getStatus() // error
^
TestInvisibleDefs_fail.scala:12: error: value setStatus is not a member of tastytest.InvisibleDefs.MyBean
mybean.setStatus("closed") // error
^
4 errors
15 changes: 15 additions & 0 deletions test/tasty/neg/src-2/TestInvisibleDefs_fail.scala
@@ -0,0 +1,15 @@
package tastytest

object TestInvisibleDefs {

def foo: tastytest.argIsHello = ??? // has invisible flag so should not be seen
def bar: tastytest.argIsHello = ??? // second try on same type

def testBean = {
val mybean = new InvisibleDefs.MyBean
mybean.status = "open"
mybean.getStatus() // error
mybean.setStatus("closed") // error
}

}
16 changes: 16 additions & 0 deletions test/tasty/neg/src-3/InvisibleDefs.scala
@@ -0,0 +1,16 @@
package tastytest

import scala.beans.BeanProperty

object InvisibleDefs {

@main def argIsHello(arg: String): Unit = assert(arg == "Hello")

class MyBean {

@BeanProperty
var status = ""

}

}
15 changes: 15 additions & 0 deletions test/tasty/run/src-2/tastytest/TestInvisibleDefs.scala
@@ -0,0 +1,15 @@
package tastytest

object TestInvisibleDefs extends Suite("TestInvisibleDefs") {

test("invoke '@main def argIsHello'") {
InvisibleDefs.argIsHello("Hello")
}

test("update bean.status") {
val mybean = new InvisibleDefs.MyBean
mybean.status = "open"
assert(mybean.status === "open")
}

}
16 changes: 16 additions & 0 deletions test/tasty/run/src-3/tastytest/InvisibleDefs.scala
@@ -0,0 +1,16 @@
package tastytest

import scala.beans.BeanProperty

object InvisibleDefs {

@main def argIsHello(arg: String): Unit = assert(arg == "Hello")

class MyBean {

@BeanProperty
var status = ""

}

}

0 comments on commit 20ae390

Please sign in to comment.