
scala.tools.nsc.backend.jvm.ScalacBackendInterface.scala Maven / Gradle / Ivy
package scala.tools.nsc.backend.jvm
import scala.collection.generic.Clearable
import scala.collection.mutable
import scala.reflect.ClassTag
import scala.reflect.internal.util.WeakHashSet
import scala.tools.nsc.Global
import scala.tools.asm
import scala.reflect.io.AbstractFile
import scala.language.implicitConversions
import scala.reflect.internal.{Flags => IFlags}
/* Uses pre-allocated objects to not allocate objects during pattern matching and during implicit conversion.
* Due to this every instance in not threadsafe, but multiple instances could be used in parrallel if underlying compiler
* supports this
*/
class ScalacBackendInterface[G <: Global](val global: G) extends BackendInterface with BackendInterfaceDefinitions{
import global._
import definitions._
type Symbol = global.Symbol
type Type = global.Type
type Annotation = global.AnnotationInfo
type Tree = global.Tree
type CompilationUnit = global.CompilationUnit
type Constant = global.Constant
type Literal = global.Literal
type Position = global.Position
type Name = global.Name
type LabelDef = global.LabelDef
type ClassDef = global.ClassDef
type TypeDef = global.TypeDef
type Apply = global.Apply
type TypeApply = global.TypeApply
type Try = global.Try
type Assign = global.Assign
type Ident = global.Ident
type If = global.If
type ValDef = global.ValDef
type Throw = global.Throw
type Return = global.Return
type Block = global.Block
type Typed = global.Typed
type ArrayValue = global.ArrayValue
type Match = global.Match
type This = global.This
type CaseDef = global.CaseDef
type Alternative = global.Alternative
type DefDef = global.DefDef
type ModuleDef = global.ModuleDef
type Template = global.Template
type Select = global.Select
type Bind = global.Bind
type New = global.New
type ApplyDynamic = global.ApplyDynamic
type Super = global.Super
type Modifiers = global.Modifiers
val NoSymbol = global.NoSymbol
val NoPosition: Position = global.NoPosition
val EmptyTree: Tree = global.EmptyTree
import scala.tools.nsc.symtab._
def currentUnit: CompilationUnit = global.currentUnit
// todo: always use same helper instances
implicit def symHelper(s: Symbol): SymbolHelper = new ScalacSymbolHelper {
def sym: Symbol = s
}
implicit def typeHelper(tp: Type): TypeHelper = new ScalaCTypeHelper {
val t = tp
}
implicit def nameHelper(nm: Name): NameHelper = new ScalacNameHelper {
val n: Name = nm
}
implicit def annotHelper(a: Annotation): AnnotationHelper = new ScalacAnnotationHelper {
val t: Annotation = a
}
implicit def treeHelper(a: Tree): TreeHelper = new ScalacTreeHelper {
val t: Tree = a
}
implicit def constantHelper(a: Constant): ConstantHelper = new ScalacConstantHelper {
val c: Constant = a
}
implicit def positionHelper(a: Position): PositionHelper = new ScalacPositionHelper {
val p: Position = a
}
val UnitTag: ConstantTag = global.UnitTag
val IntTag: ConstantTag = global.IntTag
val FloatTag: ConstantTag = global.FloatTag
val NullTag: ConstantTag = global.NullTag
val BooleanTag: ConstantTag = global.BooleanTag
val ByteTag: ConstantTag = global.ByteTag
val ShortTag: ConstantTag = global.ShortTag
val CharTag: ConstantTag = global.CharTag
val DoubleTag: ConstantTag = global.DoubleTag
val LongTag: ConstantTag = global.LongTag
val StringTag: ConstantTag = global.StringTag
val ClazzTag: ConstantTag = global.ClazzTag
val EnumTag: ConstantTag = global.EnumTag
val hashMethodSym: Symbol = getMember(ScalaRunTimeModule, nme.hash_)
val String_valueOf: Symbol = getMember(StringModule, nme.valueOf).filter(sym => sym.info.paramTypes match {
case List(pt) => pt.typeSymbol == ObjectClass
case _ => false
})
val UnitClass: Symbol = global.definitions.UnitClass
val BooleanClass: Symbol = global.definitions.BooleanClass
val CharClass: Symbol = global.definitions.CharClass
val ShortClass: Symbol = global.definitions.ShortClass
val ClassClass: Symbol = global.definitions.ClassClass
val ByteClass: Symbol = global.definitions.ByteClass
val IntClass: Symbol = global.definitions.IntClass
val LongClass: Symbol = global.definitions.LongClass
val FloatClass: Symbol = global.definitions.FloatClass
val DoubleClass: Symbol = global.definitions.DoubleClass
val ArrayClass: Symbol = global.definitions.ArrayClass
val NothingClass: Symbol = global.definitions.NothingClass
val NullClass: Symbol = global.definitions.NullClass
val ObjectClass: Symbol = global.definitions.ObjectClass
val Object_isInstanceOf: Symbol = global.definitions.Object_isInstanceOf
val Object_asInstanceOf: Symbol = global.definitions.Object_asInstanceOf
val Object_equals: Symbol = global.definitions.Object_equals
val Array_clone: Symbol = global.definitions.Array_clone
lazy val externalEqualsNumNum: Symbol = platform.externalEqualsNumNum
lazy val externalEqualsNumChar: Symbol = platform.externalEqualsNumChar
lazy val externalEqualsNumObject: Symbol = platform.externalEqualsNumObject
lazy val externalEquals: Symbol = platform.externalEquals
val MaxFunctionArity: Int = global.definitions.MaxFunctionArity
val FunctionClass: Array[Symbol] = global.definitions.FunctionClass.seq.toArray
val AbstractFunctionClass: Array[Symbol] = global.definitions.AbstractFunctionClass.seq.toArray
val PartialFunctionClass: Symbol = global.definitions.PartialFunctionClass
val AbstractPartialFunctionClass: Symbol = global.definitions.AbstractPartialFunctionClass
object Assign extends AssignDeconstructor {
def _1: Tree = field.lhs
def _2: Tree = field.rhs
}
object Select extends SelectDeconstructor {
def _1: Tree = field.qualifier
def _2: Name = field.name
}
object Apply extends ApplyDeconstructor {
def _1: Tree = field.fun
def _2: List[Tree] = field.args
}
object If extends IfDeconstructor {
def _1: Tree = field.cond
def _2: Tree = field.thenp
def _3: Tree = field.elsep
}
object ValDef extends ValDefDeconstructor {
def _1: Modifiers = field.mods
def _2: Name = field.name
def _3: Tree = field.tpt
def _4: Tree = field.rhs
}
object Throw extends ThrowDeconstructor {
def unapply(s: Throw): Option[Tree] = Some(s.expr)
}
object New extends NewDeconstructor {
def unapply(s: New): Option[Type] = Some(s.tpt.tpe)
}
object ApplyDynamic extends ApplyDynamicDeconstructor {
def _1: Tree = field.qual
def _2: List[Tree] = field.args
}
object This extends ThisDeconstructor {
def unapply(s: This): Option[Name] = Some(s.qual)
def apply(s: global.Symbol): This = global.This(s.name.toTypeName) setSymbol s
}
object Ident extends IdentDeconstructor {
def unapply(s: Ident): Option[Name] = Some(s.name)
}
object Try extends TryDeconstructor {
def _1: Tree = field.block
def _2: List[Tree] = field.catches
def _3: Tree = field.finalizer
}
object Return extends ReturnDeconstructor {
def unapply(s: Return): Option[Tree] = Some(s.expr)
}
object LabelDef extends LabelDeconstructor {
def _1: Name = field.name
def _2: List[Ident] = field.params
def _3: Tree = field.rhs
}
object Literal extends LiteralDeconstructor {
def unapply(a: Literal): Option[Constant] = Some(a.value)
}
object Typed extends TypedDeconstrutor {
def _1: Tree = field.expr
def _2: Tree = field.tpt
}
object Super extends SuperDeconstructor {
def _1: Tree = field.qual
def _2: Name = field.mix
}
object ArrayValue extends ArrayValueDeconstructor {
def _1: Tree = field.elemtpt
def _2: List[Tree] = field.elems
}
object Match extends MatchDeconstructor {
def _1: Tree = field.selector
def _2: List[Tree] = field.cases
}
object Block extends BlockDeconstructor {
def _1: List[Tree] = field.stats
def _2: Tree = field.expr
}
object TypeApply extends TypeApplyDeconstructor {
def _1: Tree = field.fun
def _2: List[Tree] = field.args
}
object CaseDef extends CaseDeconstructor {
def _1: Tree = field.pat
def _2: Tree = field.guard
def _3: Tree = field.body
}
object Alternative extends AlternativeDeconstructor {
def unapply(s: Alternative): Option[List[Tree]] = Some(s.trees)
}
object Constant extends ConstantDeconstructor {
def unapply(a: Constant): Option[Any] = Some(a.value)
}
object ThrownException extends ThrownException {
def unapply(a: Annotation): Option[Symbol] = None // todo
}
object DefDef extends DefDefDeconstructor {
def _1: Modifiers = field.mods
def _2: Name = field.name
def _3: List[TypeDef] = field.tparams
def _4: List[List[ValDef]] = field.vparamss
def _5: Tree = field.tpt
def _6: Tree = field.rhs
}
object ModuleDef extends ModuleDefDeconstructor {
def _1: Modifiers = field.mods
def _2: Name = field.name
def _3: Tree = field.impl
}
object Template extends TemplateDeconstructor {
def _1: List[Tree] = field.parents
def _2: ValDef = field.self
def _3: List[Tree] = field.body
}
object Bind extends BindDeconstructor {
def _1: Name = field.name
def _2: Tree = field.body
}
object ClassDef extends ClassDefDeconstructor {
def _1: Modifiers = field.mods
def _2: Name = field.name
def _4: Template = field.impl
def _3: List[TypeDef] = field.tparams
}
object ScalacPrimitives extends Primitives {
def getPrimitive(methodSym: Symbol, reciever: Type): Int = global.scalaPrimitives.getPrimitive(methodSym, reciever)
def getPrimitive(sym: Symbol): Int = global.scalaPrimitives.getPrimitive(sym)
def isPrimitive(sym: Symbol): Boolean = global.scalaPrimitives.isPrimitive(sym)
}
val primitives: Primitives = ScalacPrimitives
val nme_This: Name = nme.This
val nme_EMPTY_PACKAGE_NAME: Name = nme.EMPTY_PACKAGE_NAME
val nme_CONSTRUCTOR: Name = nme.CONSTRUCTOR
val nme_WILDCARD: Name = nme.WILDCARD
val nme_THIS: Name = nme.THIS
val nme_PACKAGE: Name = nme.PACKAGE
val nme_EQEQ_LOCAL_VAR: Name = nme.EQEQ_LOCAL_VAR
val nme_valueOf: Name = nme.valueOf
val Flag_METHOD: Flags = IFlags.METHOD
val Flag_SYNTHETIC: Flags = IFlags.SYNTHETIC
def debuglog(msg: => String): Unit = global.debuglog(msg)
def error(pos: Position, msg: String): Unit = global.reporter.error(pos, msg)
def warning(pos: Position, msg: String): Unit = global.reporter.warning(pos, msg)
def abort(msg: String): Nothing = global.abort(msg)
def debuglevel: Int = settings.debuginfo.indexOfChoice
def settings_debug: Boolean = settings.debug
/* means of getting class symbols from compiler */
def requiredClass[T: ClassTag]: Symbol = rootMirror.requiredClass(implicitly[ClassTag[T]])
def requiredModule[T: ClassTag]: Symbol = rootMirror.requiredModule(implicitly[ClassTag[T]])
def getRequiredClass(fullname: String): Symbol = rootMirror.getRequiredClass(fullname)
def getClassIfDefined(fullname: String): Symbol = rootMirror.getClassIfDefined(fullname)
def shouldEmitAnnotation(annot: Annotation): Boolean = {
annot.symbol.initialize.isJavaDefined &&
annot.matches(ClassfileAnnotationClass) &&
retentionPolicyOf(annot) != AnnotationRetentionPolicySourceValue &&
annot.args.isEmpty
}
def isRuntimeVisible(annot: Annotation): Boolean = {
annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr) match {
case Some(retentionAnnot) =>
retentionAnnot.assocs.contains(nme.value -> LiteralAnnotArg(new Constant(AnnotationRetentionPolicyRuntimeValue)))
case _ =>
// SI-8926: if the annotation class symbol doesn't have a @RetentionPolicy annotation, the
// annotation is emitted with visibility `RUNTIME`
true
}
}
private def retentionPolicyOf(annot: AnnotationInfo): Symbol =
annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr).map(_.assocs).map(assoc =>
assoc.collectFirst {
case (`nme`.value, LiteralAnnotArg(Constant(value: Symbol))) => value
}).flatten.getOrElse(AnnotationRetentionPolicyClassValue)
lazy val AnnotationRetentionPolicyModule = AnnotationRetentionPolicyAttr.companionModule
lazy val AnnotationRetentionPolicySourceValue = AnnotationRetentionPolicyModule.tpe.member(TermName("SOURCE"))
lazy val AnnotationRetentionPolicyClassValue = AnnotationRetentionPolicyModule.tpe.member(TermName("CLASS"))
lazy val AnnotationRetentionPolicyRuntimeValue = AnnotationRetentionPolicyModule.tpe.member(TermName("RUNTIME"))
def informProgress(msg: String): Unit = if (settings.verbose) inform("[" + msg + "]")
val ExcludedForwarderFlags: Flags = {
import scala.tools.nsc.symtab.Flags._
// Should include DEFERRED but this breaks findMember.
SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO
}
val MODULE_INSTANCE_FIELD = nme.MODULE_INSTANCE_FIELD.toString
def internalNameString(offset: Int, length: Int) = new String(global.chrs, offset, length)
def targetPlatform: String = settings.target.value
def setMainClass(name: String): Unit = settings.mainClass.value = name
override def emitAsmp = if (settings.Ygenasmp.isSetByUser) Some(settings.Ygenasmp.value) else None
override def dumpClasses: Option[String] = if(settings.Ydumpclasses.isSetByUser) Some(settings.Ydumpclasses.value) else None
override def mainClass = {
if (settings.mainClass.isDefault) None
else Some(settings.mainClass.value)
}
object scalacCaches extends Caches{
def recordCache[T <: Clearable](cache: T): T = global.perRunCaches.recordCache(cache)
def newAnyRefMap[K <: AnyRef, V](): mutable.AnyRefMap[K, V] = global.perRunCaches.newAnyRefMap()
def newWeakMap[K, V](): mutable.WeakHashMap[K, V] = global.perRunCaches.newWeakMap()
def newWeakSet[K <: AnyRef](): WeakHashSet[K] = global.perRunCaches.newWeakSet()
def newMap[K, V](): mutable.HashMap[K, V] = global.perRunCaches.newMap()
def newSet[K](): mutable.Set[K] = global.perRunCaches.newSet()
}
def perRunCaches: Caches = scalacCaches
/* backend actually uses free names to generate stuff. This should NOT mangled */
def newTermName(prefix: String): Name = global.newTermName(prefix)
def isMaybeBoxed(sym: Symbol): Boolean = global.platform.isMaybeBoxed(sym)
def getSingleOutput: Option[AbstractFile] = settings.outputDirs.getSingleOutput
override def boxMethods = currentRun.runDefinitions.boxMethod
// (class, method)
override def unboxMethods = currentRun.runDefinitions.unboxMethod
trait ScalacSymbolHelper extends SymbolHelper {
def sym: Symbol
// names
def fullName(sep: Char): String = sym.fullName(sep)
def fullName: String = sym.fullName
def simpleName: Name = sym.simpleName
def javaSimpleName: Name = sym.javaSimpleName
def javaBinaryName: Name = sym.javaBinaryName
def javaClassName: String = sym.javaClassName
def name: Name = sym.name
def rawname: Name = sym.rawname
def nestedClasses: List[Symbol] = exitingPhase(currentRun.lambdaliftPhase)(sym.memberClasses)
// types
def info: Type = sym.info
def tpe: Type = sym.tpe
def thisType: Type = sym.thisType
// tests
def isClass: Boolean = sym.isClass
def isType: Boolean = sym.isType
def isAnonymousClass: Boolean = sym.isAnonymousClass
def isConstructor: Boolean = sym.isConstructor
def isAnonymousFunction: Boolean = sym.isAnonymousFunction
def isMethod: Boolean = sym.isMethod
def isPublic: Boolean = sym.isPublic
def isSynthetic: Boolean = sym.isSynthetic
def isPackageClass: Boolean = sym.isPackageClass
def isModuleClass: Boolean = sym.isModuleClass
def isModule: Boolean = sym.isModule
def isStrictFP: Boolean = sym.isStrictFP
def isLabel: Boolean = sym.isLabel
def hasPackageFlag: Boolean = sym.hasPackageFlag
def isImplClass: Boolean = sym.isImplClass
def isInterface: Boolean = sym.isInterface
def hasGetter: Boolean = sym.hasGetter
def isGetter: Boolean = sym.isGetter
def isSetter: Boolean = sym.isSetter
def isJavaDefined: Boolean = sym.isJavaDefined
def isDeferred: Boolean = sym.isDeferred
def isStaticMember: Boolean = sym.isStaticMember
def isBottomClass: Boolean = sym.isBottomClass
def isBridge: Boolean = sym.isBridge
def isArtifact: Boolean = sym.isArtifact
def hasEnumFlag: Boolean = sym.hasEnumFlag
def hasAccessBoundary: Boolean = sym.hasAccessBoundary
def isVarargsMethod: Boolean = sym.isVarargsMethod
def isDeprecated: Boolean = sym.isDeprecated
def isMutable: Boolean = sym.isMutable
def hasAbstractFlag: Boolean = sym.hasAbstractFlag
def hasModuleFlag: Boolean = sym.hasModuleFlag
def isNonBottomSubClass(sym2: Symbol): Boolean = sym.isNonBottomSubClass(sym2)
def isGetClass: Boolean = definitions.isGetClass(sym)
def hasAnnotation(sym2: Symbol): Boolean = sym.hasAnnotation(sym2)
def isClassConstructor: Boolean = sym.isClassConstructor
def isStaticConstructor: Boolean = sym.isStaticConstructor
// navigation
def owner: Symbol = sym.owner
def rawowner: Symbol = sym.rawowner
def originalOwner: Symbol = sym.originalOwner
def parentSymbols: List[Symbol] = sym.parentSymbols
def superClass: Symbol = sym.superClass
def enclClass: Symbol = sym.enclClass
def linkedClassOfClass: Symbol = sym.linkedClassOfClass
def companionClass: Symbol = sym.companionClass
def companionModule: Symbol = sym.companionModule
def companionSymbol: Symbol = sym.companionSymbol
def moduleClass: Symbol = sym.moduleClass
def primaryConstructor: Symbol = sym.primaryConstructor
def annotations: List[Annotation] = sym.annotations
def moduleSuffix: String = sym.moduleSuffix
def getter(clz: Symbol): Symbol = sym.getterIn(clz)
def outputDirectory: AbstractFile = settings.outputDirs outputDirFor enteringFlatten(sym.sourceFile)
def freshLocal(cunit: CompilationUnit, name: String, pos: Position, flags: Flags): Symbol = {
sym.newVariable(cunit.freshTermName(name), pos, flags)
}
def setter(clz: Symbol): Symbol = sym.setterIn(clz)
def serialVUID: Option[Long] = sym getAnnotation definitions.SerialVersionUIDAttr collect {
case AnnotationInfo(_, _, (_, LiteralAnnotArg(const)) :: Nil) => const.longValue
}
def pos: Position = sym.pos
def throwsAnnotations: List[Symbol] = sym.throwsAnnotations()
/**
* The member classes of a class symbol. Note that the result of this method depends on the
* current phase, for example, after lambdalift, all local classes become member of the enclosing
* class.
*/
def memberClasses: List[Symbol] = sym.info.decls.collect({
case sym if sym.isClass =>
sym
case sym if sym.isModule =>
val r = exitingPickler(sym.moduleClass)
assert(r != NoSymbol, sym.fullLocationString)
r
})(collection.breakOut)
def addRemoteRemoteExceptionAnnotation: Unit = {
val c = new Constant(RemoteExceptionClass.tpe)
val arg = new Literal(c) setType c.tpe
sym.addAnnotation(appliedType(definitions.ThrowsClass, c.tpe), arg)
}
def linkedClass: Symbol = exitingPickler(sym.linkedClassOfClass) // linkedCoC does not work properly in late phases
def companionModuleMembers: List[Symbol] = {
// phase travel to exitingPickler: this makes sure that memberClassesOf only sees member classes,
// not local classes of the companion module (E in the exmaple) that were lifted by lambdalift.
if (linkedClass.isTopLevelModuleClass) exitingPickler(linkedClass.memberClasses)
else Nil
}
/**
* All interfaces implemented by a class, except for those inherited through the superclass.
*
*/
def superInterfaces: List[Symbol] = {
// Additional interface parents based on annotations and other cues
def newParentForAnnotation(ann: AnnotationInfo): Symbol =
if (ann.symbol eq RemoteAttr) RemoteInterfaceClass
else NoSymbol
val superInterfaces0: List[Symbol] = sym.mixinClasses
val superInterfaces = existingSymbols(superInterfaces0 ++ sym.annotations.map(newParentForAnnotation)).distinct
assert(!superInterfaces.contains(NoSymbol), s"found NoSymbol among: ${superInterfaces.mkString(", ")}")
assert(superInterfaces.forall(s => s.isInterface || s.isTrait), s"found non-interface among: ${superInterfaces.mkString(", ")}")
erasure.minimizeInterfaces(superInterfaces.map(_.info)).map(_.typeSymbol)
}
/**
* True for module classes of package level objects. The backend will generate a mirror class for
* such objects.
*/
def isTopLevelModuleClass: Boolean = exitingPickler {
// phase travel to pickler required for isNestedClass (looks at owner)
val r = sym.isModuleClass && !sym.isNestedClass
// The mixin phase adds the `lateMODULE` flag to trait implementation classes. Since the flag
// is late, it should not be visible here inside the time travel. We check this.
if (r) assert(!sym.isImplClass, s"isModuleClass should be false for impl class $sym")
r
}
/**
* True for module classes of modules that are top-level or owned only by objects. Module classes
* for such objects will get a MODULE$ flag and a corresponding static initializer.
*/
def isStaticModuleClass: Boolean = {
/* (1) Phase travel to to pickler is required to exclude implementation classes; they have the
* lateMODULEs after mixin, so isModuleClass would be true.
* (2) isStaticModuleClass is a source-level property. See comment on isOriginallyStaticOwner.
*/
exitingPickler { // (1)
sym.isModuleClass &&
sym.originalOwner.isOriginallyStaticOwner // (2)
}
}
/**
* This is basically a re-implementation of sym.isStaticOwner, but using the originalOwner chain.
*
* The problem is that we are interested in a source-level property. Various phases changed the
* symbol's properties in the meantime, mostly lambdalift modified (destructively) the owner.
* Therefore, `sym.isStatic` is not what we want. For example, in
* object T { def f { object U } }
* the owner of U is T, so UModuleClass.isStatic is true. Phase travel does not help here.
*/
def isOriginallyStaticOwner: Boolean = {
sym.isPackageClass || sym.isModuleClass && sym.originalOwner.isOriginallyStaticOwner
}
def isSynchronized: Boolean = sym.hasFlag(Flags.SYNCHRONIZED)
def enclosingClassSym: Symbol = {
if (sym.isJavaDefined && sym.rawowner.isModuleClass) {
// Example java source: class C { static class D { } }
// The Scala compiler creates a class and a module symbol for C. Because D is a static
// nested class, the symbol for D is nested in the module class C (not in the class C).
// For the InnerClass attribute, we use the class symbol C, which represents the situation
// in the source code.
// Cannot use innerClassSym.isStatic: this method looks at the owner, which is a package
// at this pahse (after lambdalift, flatten).
assert(sym.originalOwner.isOriginallyStaticOwner, sym.originalOwner)
// phase travel for linkedCoC - does not always work in late phases
exitingPickler(sym.rawowner.linkedClassOfClass)
}
else sym.rawowner
}
def fieldSymbols: List[Symbol] = {
for (f <- sym.info.decls.toList ;
if !f.isMethod && f.isTerm && !f.isModule
) yield f
}
def methodSymbols: List[Symbol] = {
// cd.impl.body collect { case dd: DefDef => dd.symbol }
for (f <- sym.info.decls.toList ;
if f.isMethod
) yield f
}
def shouldEmitForwarders: Boolean = {
exitingPickler { !(sym.name.toString contains '$') && sym.hasModuleFlag && !sym.isImplClass && !sym.isNestedClass }
}
def isPrivate: Boolean = {
// constructors of module classes should be private. introduced in b06edbc, probably to prevent
// creating module instances from java. for nested modules, the constructor needs to be public
// since they are created by the outer class and stored in a field. a java client can create
// new instances via outerClassInstance.new InnerModuleClass$().
// TODO: do this early, mark the symbol private.
sym.isPrivate || (sym.isPrimaryConstructor && sym.owner.isTopLevelModuleClass)
}
def isFinal: Boolean = {
// Symbols marked in source as `final` have the FINAL flag. (In the past, the flag was also
// added to modules and module classes, not anymore since 296b706).
// Note that the presence of the `FINAL` flag on a symbol does not correspond 1:1 to emitting
// ACC_FINAL in bytecode.
//
// Top-level modules are marked ACC_FINAL in bytecode (even without the FINAL flag). Nested
// objects don't get the flag to allow overriding (under -Yoverride-objects, SI-5676).
//
// For fields, only eager val fields can receive ACC_FINAL. vars or lazy vals can't:
// Source: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
// "Another problem is that the specification allows aggressive
// optimization of final fields. Within a thread, it is permissible to
// reorder reads of a final field with those modifications of a final
// field that do not take place in the constructor."
//
// A var or lazy val which is marked final still has meaning to the
// scala compiler. The word final is heavily overloaded unfortunately;
// for us it means "not overridable". At present you can't override
// vars regardless; this may change.
//
// The logic does not check .isFinal (which checks flags for the FINAL flag,
// and includes symbols marked lateFINAL) instead inspecting rawflags so
// we can exclude lateFINAL. Such symbols are eligible for inlining, but to
// avoid breaking proxy software which depends on subclassing, we do not
// emit ACC_FINAL.
(
(((sym.rawflags & Flags.FINAL) != 0) || sym.isTopLevelModuleClass)
&& !sym.enclClass.isInterface
&& !sym.isClassConstructor
&& !sym.isMutable // lazy vals and vars both
)
}
def isJavaEntryPoint: Boolean = {
def fail(msg: String, pos: Position = sym.pos) = {
reporter.warning(sym.pos,
sym.name +
s" has a main method with parameter type Array[String], but ${sym.fullName('.')} will not be a runnable program.\n Reason: $msg"
// TODO: make this next claim true, if possible
// by generating valid main methods as static in module classes
// not sure what the jvm allows here
// + " You can still run the program by calling it as " + sym.javaSimpleName + " instead."
)
false
}
def failNoForwarder(msg: String) = {
fail(s"$msg, which means no static forwarder can be generated.\n")
}
val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil
val hasApproximate = possibles exists { m =>
m.info match {
case MethodType(p :: Nil, _) => p.tpe.typeSymbol == definitions.ArrayClass
case _ => false
}
}
// At this point it's a module with a main-looking method, so either succeed or warn that it isn't.
hasApproximate && {
// Before erasure so we can identify generic mains.
enteringErasure {
val companion = sym.linkedClassOfClass
if (definitions.hasJavaMainMethod(companion))
failNoForwarder("companion contains its own main method")
else if (companion.tpe.member(nme.main) != NoSymbol)
// this is only because forwarders aren't smart enough yet
failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)")
else if (companion.isTrait)
failNoForwarder("companion is a trait")
// Now either succeeed, or issue some additional warnings for things which look like
// attempts to be java main methods.
else (possibles exists definitions.isJavaMainMethod) || {
possibles exists { m =>
m.info match {
case PolyType(_, _) =>
fail("main methods cannot be generic.")
case MethodType(params, res) =>
if (res.typeSymbol :: params exists (_.isAbstractType))
fail("main methods cannot refer to type parameters or abstract types.", m.pos)
else
definitions.isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos)
case tp =>
fail(s"don't know what this is: $tp", m.pos)
}
}
}
}
}
}
}
def log(msg: => String): Unit = global synchronized { global.log(msg) }
def sourceFileFor(cu: CompilationUnit): String = cu.source.toString
def noForwarders: Boolean = settings.noForwarders
var pickledBytes = 0
/* Returns a ScalaSignature annotation if it must be added to this class, none otherwise.
* This annotation must be added to the class' annotations list when generating them.
*
* Depending on whether the returned option is defined, it adds to `jclass` one of:
* (a) the ScalaSig marker attribute
* (indicating that a scala-signature-annotation aka pickle is present in this class); or
* (b) the Scala marker attribute
* (indicating that a scala-signature-annotation aka pickle is to be found in another file).
*
*
* @param jclassName The class file that is being readied.
* @param sym The symbol for which the signature has been entered in the symData map.
* This is different than the symbol
* that is being generated in the case of a mirror class.
* @return An option that is:
* - defined and contains an AnnotationInfo of the ScalaSignature type,
* instantiated with the pickle signature for sym.
* - empty if the jclass/sym pair must not contain a pickle.
*
* must-single-thread
*/
def getAnnotPickle(jclassName: String, sym: Symbol): Option[AnnotationInfo] = {
currentRun.symData get sym match {
case Some(pickle) if !nme.isModuleName(newTermName(jclassName)) =>
val scalaAnnot = {
val sigBytes = ScalaSigBytes(pickle.bytes.take(pickle.writeIndex))
AnnotationInfo(sigBytes.sigAnnot, Nil, (nme.bytes, sigBytes) :: Nil)
}
pickledBytes += pickle.writeIndex
currentRun.symData -= sym
currentRun.symData -= sym.companionSymbol
Some(scalaAnnot)
case _ =>
None
}
}
trait ScalaCTypeHelper extends TypeHelper {
def t: Type
def members: List[Symbol] = t.members.toList
def <:<(other: Type): Boolean = t <:< other
def isFinalType: Boolean = t.isFinalType
def member(string: Name): Symbol = t.member(string)
def paramTypes: List[Type] = t.paramTypes
def underlying: Type = t.underlying
def memberInfo(s: Symbol): Type = t.memberInfo(s)
def decls: List[Symbol] = t.decls.toList
def typeSymbol: Symbol = t.typeSymbol
def =:=(other: Type): Boolean = t =:= other
def membersBasedOnFlags(excludedFlags: Flags, requiredFlags: Flags): List[Symbol] = t.membersBasedOnFlags(excludedFlags, requiredFlags).toList
def resultType: Type = t.resultType
def summaryString: String = t.summaryString
def parents: List[Type] = t.parents
def params: List[Symbol] = t.params
/**
* This method returns the BType for a type reference, for example a parameter type.
*
* If the result is a ClassBType for a nested class, it is added to the innerClassBufferASM.
*
* If `t` references a class, toTypeKind ensures that the class is not an implementation class.
* See also comment on getClassBTypeAndRegisterInnerClass, which is invoked for implementation
* classes.
*/
def toTypeKind(ctx: BCodeHelpers)(storage: ctx.BCInnerClassGen): ctx.bTypes.BType = {
import ctx.bTypes._
import coreBTypes._
/**
* Primitive types are represented as TypeRefs to the class symbol of, for example, scala.Int.
* The `primitiveTypeMap` maps those class symbols to the corresponding PrimitiveBType.
*/
def primitiveOrClassToBType(sym: Symbol): BType = {
assert(sym.isClass, sym)
assert(sym != ArrayClass || isCompilingArray, sym)
primitiveTypeMap.getOrElse(sym, storage.getClassBTypeAndRegisterInnerClass(sym.asInstanceOf[ctx.int.Symbol]))
}
/**
* When compiling Array.scala, the type parameter T is not erased and shows up in method
* signatures, e.g. `def apply(i: Int): T`. A TyperRef to T is replaced by ObjectReference.
*/
def nonClassTypeRefToBType(sym: Symbol): ClassBType = {
assert(sym.isType && isCompilingArray, sym)
ObjectReference
}
t.dealiasWiden match {
case TypeRef(_, ArrayClass, List(arg)) => ArrayBType(arg.toTypeKind(ctx)(storage)) // Array type such as Array[Int] (kept by erasure)
case TypeRef(_, sym, _) if !sym.isClass => nonClassTypeRefToBType(sym) // See comment on nonClassTypeRefToBType
case TypeRef(_, sym, _) => primitiveOrClassToBType(sym) // Common reference to a type such as scala.Int or java.lang.String
case ClassInfoType(_, _, sym) => primitiveOrClassToBType(sym) // We get here, for example, for genLoadModule, which invokes toTypeKind(moduleClassSymbol.info)
/* AnnotatedType should (probably) be eliminated by erasure. However we know it happens for
* meta-annotated annotations (@(ann @getter) val x = 0), so we don't emit a warning.
* The type in the AnnotationInfo is an AnnotatedTpe. Tested in jvm/annotations.scala.
*/
case a @ AnnotatedType(_, t) =>
debuglog(s"typeKind of annotated type $a")
t.toTypeKind(ctx)(storage)
/* ExistentialType should (probably) be eliminated by erasure. We know they get here for
* classOf constants:
* class C[T]
* class T { final val k = classOf[C[_]] }
*/
case e @ ExistentialType(_, t) =>
debuglog(s"typeKind of existential type $e")
t.toTypeKind(ctx)(storage)
/* The cases below should probably never occur. They are kept for now to avoid introducing
* new compiler crashes, but we added a warning. The compiler / library bootstrap and the
* test suite don't produce any warning.
*/
case tp =>
currentUnit.warning(tp.typeSymbol.pos,
s"an unexpected type representation reached the compiler backend while compiling $currentUnit: $tp. " +
"If possible, please file a bug on issues.scala-lang.org.")
tp match {
case ThisType(ArrayClass) => ObjectReference // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
case ThisType(sym) => storage.getClassBTypeAndRegisterInnerClass(sym.asInstanceOf[ctx.int.Symbol])
case SingleType(_, sym) => primitiveOrClassToBType(sym)
case ConstantType(_) => t.underlying.toTypeKind(ctx)(storage)
case RefinedType(parents, _) => parents.map(_.toTypeKind(ctx)(storage).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b))
}
}
}
}
trait ScalacNameHelper extends NameHelper{
val n: Name
import global.AnyNameOps
def offset: Int = n.start
def toTypeName: Name = n.toTypeName
def isTypeName: Boolean = n.isTypeName
def toTermName: Name = n.toTermName
def dropModule: Name = AnyNameOps(n).dropModule
def len: Int = n.length
def isTermName: Boolean = n.isTermName
def startsWith(s: String): Boolean = n.startsWith(s)
}
trait ScalacTreeHelper extends TreeHelper{
val t: Tree
def symbol: Symbol = t.symbol
def pos: Position = t.pos
def isEmpty: Boolean = t.isEmpty
def tpe: Type = t.tpe
def exists(pred: (Tree) => Boolean): Boolean = t.exists(pred)
}
trait ScalacAnnotationHelper extends AnnotationHelper {
val t: Annotation
def atp: Type = t.atp
def assocs: List[(Name, Object)] = t.assocs
def symbol: Symbol = t.symbol
def args: List[Tree] = t.args
}
trait ScalacConstantHelper extends ConstantHelper{
val c: Constant
def tag: ConstantTag = c.tag
def booleanValue: Boolean = c.booleanValue
def longValue: Long = c.longValue
def byteValue: Byte = c.byteValue
def stringValue: String = c.stringValue
def symbolValue: Symbol = c.symbolValue
def floatValue: Float = c.floatValue
def value: Any = c.value
def typeValue: Type = c.typeValue
def shortValue: Short = c.shortValue
def intValue: Int = c.intValue
def doubleValue: Double = c.doubleValue
def charValue: Char = c.charValue
}
trait ScalacPositionHelper extends PositionHelper{
val p: Position
def isDefined: Boolean = p.isDefined
def line: Int = p.line
def finalPosition: Position = p.finalPosition
}
def isQualifierSafeToElide(qual: Tree): Boolean = treeInfo isQualifierSafeToElide qual
def isBox(sym: Symbol): Boolean = currentRun.runDefinitions.isBox(sym)
def isUnbox(sym: Symbol): Boolean = currentRun.runDefinitions.isUnbox(sym)
/*
* For arg a LiteralAnnotArg(constt) with const.tag in {ClazzTag, EnumTag}
* as well as for arg a NestedAnnotArg
* must-single-thread
* Otherwise it's safe to call from multiple threads.
*/
private def emitArgument(av: asm.AnnotationVisitor,
name: String,
arg: ClassfileAnnotArg, bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen) {
(arg: @unchecked) match {
case LiteralAnnotArg(const) =>
if (const.isNonUnitAnyVal) { av.visit(name, const.value) }
else {
const.tag match {
case StringTag =>
assert(const.value != null, const) // TODO this invariant isn't documented in `case class Constant`
av.visit(name, const.stringValue) // `stringValue` special-cases null, but that execution path isn't exercised for a const with StringTag
case ClazzTag => av.visit(name, const.typeValue.toTypeKind(bcodeStore)(innerClasesStore).toASMType)
case EnumTag =>
val edesc = innerClasesStore.typeDescriptor(const.tpe.asInstanceOf[bcodeStore.int.Type]) // the class descriptor of the enumeration class.
val evalue = const.symbolValue.name.toString // value the actual enumeration value.
av.visitEnum(name, edesc, evalue)
}
}
case sb @ ScalaSigBytes(bytes) =>
// see http://www.scala-lang.org/sid/10 (Storage of pickled Scala signatures in class files)
// also JVMS Sec. 4.7.16.1 The element_value structure and JVMS Sec. 4.4.7 The CONSTANT_Utf8_info Structure.
if (sb.fitsInOneString) {
av.visit(name, BCodeAsmCommon.strEncode(sb))
} else {
val arrAnnotV: asm.AnnotationVisitor = av.visitArray(name)
for(arg <- BCodeAsmCommon.arrEncode(sb)) { arrAnnotV.visit(name, arg) }
arrAnnotV.visitEnd()
} // for the lazy val in ScalaSigBytes to be GC'ed, the invoker of emitAnnotations() should hold the ScalaSigBytes in a method-local var that doesn't escape.
case ArrayAnnotArg(args) =>
val arrAnnotV: asm.AnnotationVisitor = av.visitArray(name)
for(arg <- args) { emitArgument(arrAnnotV, null, arg, bcodeStore)(innerClasesStore) }
arrAnnotV.visitEnd()
case NestedAnnotArg(annInfo) =>
val AnnotationInfo(typ, args, assocs) = annInfo
assert(args.isEmpty, args)
val desc = innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]) // the class descriptor of the nested annotation class
val nestedVisitor = av.visitAnnotation(name, desc)
emitAssocs(nestedVisitor, assocs, bcodeStore)(innerClasesStore)
}
}
/*
* In general,
* must-single-thread
* but not necessarily always.
*/
private def emitAssocs(av: asm.AnnotationVisitor, assocs: List[(Name, ClassfileAnnotArg)], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen) {
for ((name, value) <- assocs) {
emitArgument(av, name.toString(), value, bcodeStore)(innerClasesStore)
}
av.visitEnd()
}
/*
* must-single-thread
*/
override def emitAnnotations(cw: asm.ClassVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen) {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
val av = cw.visitAnnotation(innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]), isRuntimeVisible(annot))
emitAssocs(av, assocs, bcodeStore)(innerClasesStore)
}
}
/*
* must-single-thread
*/
override def emitAnnotations(mw: asm.MethodVisitor, annotations: List[AnnotationInfo], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen) {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
val av = mw.visitAnnotation(innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]), isRuntimeVisible(annot))
emitAssocs(av, assocs, bcodeStore)(innerClasesStore)
}
}
/*
* must-single-thread
*/
override def emitAnnotations(fw: asm.FieldVisitor, annotations: List[AnnotationInfo], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen) {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
val av = fw.visitAnnotation(innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]), isRuntimeVisible(annot))
emitAssocs(av, assocs, bcodeStore)(innerClasesStore)
}
}
/*
* must-single-thread
*/
override def emitParamAnnotations(jmethod: asm.MethodVisitor, pannotss: List[List[AnnotationInfo]], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen) {
val annotationss = pannotss map (_ filter shouldEmitAnnotation)
if (annotationss forall (_.isEmpty)) return
for ((annots, idx) <- annotationss.zipWithIndex;
annot <- annots) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
val pannVisitor: asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]), isRuntimeVisible(annot))
emitAssocs(pannVisitor, assocs, bcodeStore)(innerClasesStore)
}
}
def getGenericSignature(sym: Symbol, owner: Symbol): String = genASM.getGenericSignature(sym, owner)
def getStaticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol): String = genASM.staticForwarderGenericSignature(sym, moduleClass)
def getLabelDefOwners(t: Tree): Map[Tree, List[LabelDef]] = {
class LabelDefsFinder extends Traverser {
val result = collection.mutable.Map.empty[Tree, List[LabelDef]]
var acc: List[LabelDef] = Nil
/*
* can-multi-thread
*/
override def traverse(tree: Tree) {
val saved = acc
acc = Nil
super.traverse(tree)
// acc contains all LabelDefs found under (but not at) `tree`
tree match {
case lblDf: LabelDef => acc ::= lblDf
case _ => ()
}
if (acc.isEmpty) {
acc = saved
} else {
result += (tree -> acc)
acc = acc ::: saved
}
}
}
val ldf = new LabelDefsFinder()
ldf.traverse(t)
ldf.result.toMap
}
implicit val TypeDefTag: ClassTag[TypeDef] = global.TypeDefTag
implicit val ApplyTag: ClassTag[Apply] = global.ApplyTag
implicit val SelectTag: ClassTag[Select] = global.SelectTag
implicit val TypeApplyTag: ClassTag[TypeApply] = global.TypeApplyTag
implicit val ClassDefTag: ClassTag[ClassDef] = global.ClassDefTag
implicit val TryTag: ClassTag[Try] = global.TryTag
implicit val AssignTag: ClassTag[Assign] = global.AssignTag
implicit val IdentTag: ClassTag[Ident] = global.IdentTag
implicit val IfTag: ClassTag[If] = global.IfTag
implicit val LabelDefTag: ClassTag[LabelDef] = global.LabelDefTag
implicit val ValDefTag: ClassTag[ValDef] = global.ValDefTag
implicit val ThrowTag: ClassTag[Throw] = global.ThrowTag
implicit val ReturnTag: ClassTag[Return] = global.ReturnTag
implicit val LiteralTag: ClassTag[Literal] = global.LiteralTag
implicit val BlockTag: ClassTag[Block] = global.BlockTag
implicit val TypedTag: ClassTag[Typed] = global.TypedTag
implicit val ArrayValueTag: ClassTag[ArrayValue] = ClassTag[ArrayValue](classOf[ArrayValue])
implicit val MatchTag: ClassTag[Match] = global.MatchTag
implicit val CaseDefTag: ClassTag[CaseDef] = global.CaseDefTag
implicit val ThisTag: ClassTag[This] = global.ThisTag
implicit val AlternativeTag: ClassTag[Alternative] = global.AlternativeTag
implicit val DefDefTag: ClassTag[DefDef] = global.DefDefTag
implicit val ModuleDefTag: ClassTag[ModuleDef] = global.ModuleDefTag
implicit val NameTag: ClassTag[Name] = global.NameTag
implicit val TemplateTag: ClassTag[Template] = global.TemplateTag
implicit val BindTag: ClassTag[Bind] = global.BindTag
implicit val NewTag: ClassTag[New] = global.NewTag
implicit val ApplyDynamicTag: ClassTag[ApplyDynamic] = ClassTag[ApplyDynamic](classOf[ApplyDynamic])
implicit val SuperTag: ClassTag[Super] = global.SuperTag
implicit val ConstantClassTag: ClassTag[Constant] = global.ConstantTag
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy