aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2014-12-17 17:35:37 +0100
committerDmitry Petrashko <dark@d-d.me>2014-12-17 17:35:37 +0100
commita68980c1d322095cdd8d7a2b45b05d901072eeb1 (patch)
tree4dae525611287d910eb41672d2022a70db3f34dc /src/dotty/tools
parent7f6d234a6aca6fd0c638aec45d867dedb2077f29 (diff)
parent4c112037290a526c66bbb782a61bcd8a60730b4b (diff)
downloaddotty-a68980c1d322095cdd8d7a2b45b05d901072eeb1.tar.gz
dotty-a68980c1d322095cdd8d7a2b45b05d901072eeb1.tar.bz2
dotty-a68980c1d322095cdd8d7a2b45b05d901072eeb1.zip
Merge pull request #251 from dotty-staging/shared-backend
Shared backend
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/backend/jvm/CollectEntryPoints.scala120
-rw-r--r--src/dotty/tools/backend/jvm/DottyBackendInterface.scala847
-rw-r--r--src/dotty/tools/backend/jvm/GenBCode.scala390
-rw-r--r--src/dotty/tools/backend/jvm/LabelDefs.scala185
-rwxr-xr-xsrc/dotty/tools/backend/jvm/scalaPrimitives.scala417
-rw-r--r--src/dotty/tools/dotc/Compiler.scala6
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala2
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala4
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala6
-rw-r--r--src/dotty/tools/dotc/core/Names.scala2
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala3
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala3
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala3
-rw-r--r--src/dotty/tools/dotc/core/Types.scala13
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala4
-rw-r--r--src/dotty/tools/dotc/transform/LambdaLift.scala10
-rw-r--r--src/dotty/tools/dotc/transform/MixinOps.scala7
-rw-r--r--src/dotty/tools/dotc/transform/SymUtils.scala29
18 files changed, 2030 insertions, 21 deletions
diff --git a/src/dotty/tools/backend/jvm/CollectEntryPoints.scala b/src/dotty/tools/backend/jvm/CollectEntryPoints.scala
new file mode 100644
index 000000000..802100bf2
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/CollectEntryPoints.scala
@@ -0,0 +1,120 @@
+package dotty.tools.backend.jvm
+
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Types
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, MiniPhase, MiniPhaseTransform}
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc
+import dotty.tools.dotc.backend.jvm.DottyPrimitives
+import dotty.tools.dotc.core.Flags.FlagSet
+import dotty.tools.dotc.transform.Erasure
+import dotty.tools.dotc.transform.SymUtils._
+import java.io.{File => JFile}
+
+import scala.collection.generic.Clearable
+import scala.collection.mutable
+import scala.reflect.ClassTag
+import scala.reflect.internal.util.WeakHashSet
+import scala.reflect.io.{Directory, PlainDirectory, AbstractFile}
+import scala.tools.asm.{ClassVisitor, FieldVisitor, MethodVisitor}
+import scala.tools.nsc.backend.jvm.{BCodeHelpers, BackendInterface}
+import dotty.tools.dotc.core._
+import Periods._
+import SymDenotations._
+import Contexts._
+import Types._
+import Symbols._
+import Denotations._
+import Phases._
+import java.lang.AssertionError
+import dotty.tools.dotc.util.Positions.Position
+import Decorators._
+import tpd._
+import StdNames.nme
+
+/**
+ * Created by dark on 26/11/14.
+ */
+class CollectEntryPoints extends MiniPhaseTransform {
+ def phaseName: String = "Collect entry points"
+
+ override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ if((tree.symbol ne NoSymbol) && CollectEntryPoints.isJavaEntyPoint(tree.symbol)) {
+ ctx.genBCodePhase.asInstanceOf[GenBCode].registerEntryPoint(tree.symbol)
+ }
+ tree
+ }
+}
+
+object CollectEntryPoints{
+ def isJavaEntyPoint(sym: Symbol)(implicit ctx: Context): Boolean = {
+ import Types.MethodType
+ val d = ctx.definitions
+ val StringType = d.StringType
+ def isJavaMainMethod(sym: Symbol) = (sym.name == nme.main) && (toDenot(sym).info match {
+ case r@ MethodType(_, List(d.ArrayType(StringType))) => r.resultType eq d.UnitType
+ case _ => false
+ })
+ // The given class has a main method.
+ def hasJavaMainMethod(sym: Symbol): Boolean =
+ (toDenot(sym).info member nme.main).alternatives exists(x => isJavaMainMethod(x.symbol))
+
+ def fail(msg: String, pos: Position = sym.pos) = {
+ ctx.warning( sym.name +
+ s" has a main method with parameter type Array[String], but ${toDenot(sym).fullName} will not be a runnable program.\n Reason: $msg",
+ sourcePos(sym.pos)
+ // 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 " + javaName(sym) + " instead."
+ )
+ false
+ }
+ def failNoForwarder(msg: String) = {
+ fail(s"$msg, which means no static forwarder can be generated.\n")
+ }
+ val possibles = if (sym.flags is Flags.Module) (toDenot(sym).info nonPrivateMember nme.main).alternatives else Nil
+ val hasApproximate = possibles exists { m =>
+ m.info match {
+ case MethodType(_, p :: Nil) =>
+ p.typeSymbol == defn.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.
+ {
+ // implicit val c = ctx.withPhase(ctx.erasurePhase)
+
+ val companion = sym.asClass.moduleClass
+
+ if (hasJavaMainMethod(companion))
+ failNoForwarder("companion contains its own main method")
+ else if (toDenot(companion).info.member(nme.main) != NoDenotation)
+ // 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.flags is Flags.Trait)
+ 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(x=> isJavaMainMethod(x.symbol))) || {
+ possibles exists { m =>
+ toDenot(m.symbol).info match {
+ case t:PolyType =>
+ fail("main methods cannot be generic.")
+ case t@MethodType(paramNames, paramTypes) =>
+ if (t.resultType :: paramTypes exists (_.typeSymbol.isAbstractType))
+ fail("main methods cannot refer to type parameters or abstract types.", m.symbol.pos)
+ else
+ isJavaMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.pos)
+ case tp =>
+ fail(s"don't know what this is: $tp", m.symbol.pos)
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
new file mode 100644
index 000000000..672e00a5c
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -0,0 +1,847 @@
+package dotty.tools.backend.jvm
+
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc
+import dotty.tools.dotc.backend.jvm.DottyPrimitives
+import dotty.tools.dotc.core.Flags.FlagSet
+import dotty.tools.dotc.transform.Erasure
+import dotty.tools.dotc.transform.SymUtils._
+import java.io.{File => JFile}
+
+import scala.collection.generic.Clearable
+import scala.collection.mutable
+import scala.reflect.ClassTag
+import scala.reflect.internal.util.WeakHashSet
+import scala.reflect.io.{Directory, PlainDirectory, AbstractFile}
+import scala.tools.asm.{ClassVisitor, FieldVisitor, MethodVisitor}
+import scala.tools.nsc.backend.jvm.{BCodeHelpers, BackendInterface}
+import dotty.tools.dotc.core._
+import Periods._
+import SymDenotations._
+import Contexts._
+import Types._
+import Symbols._
+import Denotations._
+import Phases._
+import java.lang.AssertionError
+import dotty.tools.dotc.util.{Positions, DotClass}
+import Decorators._
+import tpd._
+import StdNames.nme
+
+class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
+ trait NonExistentTree extends tpd.Tree
+ type Symbol = Symbols.Symbol
+ type Type = Types.Type
+ type Tree = tpd.Tree
+ type CompilationUnit = dotc.CompilationUnit
+ type Constant = Constants.Constant
+ type Literal = tpd.Literal
+ type Position = Positions.Position
+ type Name = Names.Name
+ type ClassDef = tpd.TypeDef
+ type TypeDef = tpd.TypeDef
+ type Apply = tpd.Apply
+ type TypeApply = tpd.TypeApply
+ type Try = tpd.Try
+ type Assign = tpd.Assign
+ type Ident = tpd.Ident
+ type If = tpd.If
+ type ValDef = tpd.ValDef
+ type Throw = tpd.Throw
+ type Return = tpd.Return
+ type Block = tpd.Block
+ type Typed = tpd.Typed
+ type Match = tpd.Match
+ type This = tpd.This
+ type CaseDef = tpd.CaseDef
+ type Alternative = tpd.Alternative
+ type DefDef = tpd.DefDef
+ type Template = tpd.Template
+ type Select = tpd.Select
+ type Bind = tpd.Bind
+ type New = tpd.New
+ type Super = tpd.Super
+ type Modifiers = tpd.Modifiers
+ type Annotation = NonExistentTree
+ type ArrayValue = tpd.JavaSeqLiteral
+ type ApplyDynamic = NonExistentTree
+ type ModuleDef = NonExistentTree
+ type LabelDef = tpd.DefDef
+ type Closure = tpd.Closure
+
+ val NoSymbol = Symbols.NoSymbol
+ val NoPosition: Position = Positions.NoPosition
+ val EmptyTree: Tree = tpd.EmptyTree
+
+
+ val UnitTag: ConstantTag = Constants.UnitTag
+ val IntTag: ConstantTag = Constants.IntTag
+ val FloatTag: ConstantTag = Constants.FloatTag
+ val NullTag: ConstantTag = Constants.NullTag
+ val BooleanTag: ConstantTag = Constants.BooleanTag
+ val ByteTag: ConstantTag = Constants.ByteTag
+ val ShortTag: ConstantTag = Constants.ShortTag
+ val CharTag: ConstantTag = Constants.CharTag
+ val DoubleTag: ConstantTag = Constants.DoubleTag
+ val LongTag: ConstantTag = Constants.LongTag
+ val StringTag: ConstantTag = Constants.StringTag
+ val ClazzTag: ConstantTag = Constants.ClazzTag
+ val EnumTag: ConstantTag = Constants.EnumTag
+
+ val nme_This: Name = StdNames.nme.This
+ val nme_EMPTY_PACKAGE_NAME: Name = StdNames.nme.EMPTY_PACKAGE
+ val nme_CONSTRUCTOR: Name = StdNames.nme.CONSTRUCTOR
+ val nme_WILDCARD: Name = StdNames.nme.WILDCARD
+ val nme_THIS: Name = StdNames.nme.THIS
+ val nme_PACKAGE: Name = StdNames.nme.PACKAGE
+ val nme_EQEQ_LOCAL_VAR: Name = StdNames.nme.EQEQ_LOCAL_VAR
+
+ val BoxesRunTimeModule = ctx.requiredModule("scala.runtime.BoxesRunTime")
+ val BoxesRunTimeClass = toDenot(BoxesRunTimeModule).moduleClass.asClass
+
+ val nme_valueOf: Name = StdNames.nme.valueOf
+ val nme_apply = StdNames.nme.apply
+ val NothingClass: Symbol = defn.NothingClass
+ val NullClass: Symbol = defn.NullClass
+ val ObjectClass: Symbol = defn.ObjectClass
+ val Object_Type: Type = defn.ObjectType
+ val Throwable_Type: Type = defn.ThrowableType
+ val Object_isInstanceOf: Symbol = defn.Any_isInstanceOf
+ val Object_asInstanceOf: Symbol = defn.Any_asInstanceOf
+ val Object_equals: Symbol = defn.Any_equals
+ val ArrayClass: Symbol = defn.ArrayClass
+ val UnitClass: Symbol = defn.UnitClass
+ val BooleanClass: Symbol = defn.BooleanClass
+ val CharClass: Symbol = defn.CharClass
+ val ShortClass: Symbol = defn.ShortClass
+ val ClassClass: Symbol = defn.ClassClass
+ val ByteClass: Symbol = defn.ByteClass
+ val IntClass: Symbol = defn.IntClass
+ val LongClass: Symbol = defn.LongClass
+ val FloatClass: Symbol = defn.FloatClass
+ val DoubleClass: Symbol = defn.DoubleClass
+ def isArrayClone(tree: Tree) = tree match {
+ case Select(qual, StdNames.nme.clone_) if qual.tpe.widen.isInstanceOf[JavaArrayType] => true
+ case _ => false
+ }
+
+ val hashMethodSym: Symbol = NoSymbol // used to dispatch ## on primitives to ScalaRuntime.hash. Should be implemented by a miniphase
+ val externalEqualsNumNum: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumNum)
+ lazy val externalEqualsNumChar: Symbol = ??? // ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumChar) // this method is private
+ val externalEqualsNumObject: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumObject)
+ val externalEquals: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equals_)
+ val MaxFunctionArity: Int = Definitions.MaxFunctionArity
+ val FunctionClass: Array[Symbol] = defn.FunctionClass.asInstanceOf[Array[Symbol]]
+ val AbstractFunctionClass: Array[Symbol] = defn.AbstractFunctionClass.asInstanceOf[Array[Symbol]]
+ val PartialFunctionClass: Symbol = defn.PartialFunctionClass
+ val AbstractPartialFunctionClass: Symbol = defn.AbstractPartialFunctionClass
+ val String_valueOf: Symbol = defn.String_valueOf_Object
+
+ def boxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses.map{x =>
+ (x, Erasure.Boxing.boxMethod(x.asClass))
+ }.toMap
+ def unboxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses.map(x => (x, Erasure.Boxing.unboxMethod(x.asClass))).toMap
+
+ private val mkArrayNames: Set[String] = Set("Byte", "Float", "Char", "Double", "Boolean", "Unit", "Long", "Int", "Short", "Ref")
+
+ override lazy val syntheticArrayConstructors: Set[Symbol] = mkArrayNames.map(nm => ctx.requiredMethod(toDenot(defn.DottyArraysModule).moduleClass.asClass, s"new${nm}Array"))
+
+ def isBox(sym: Symbol): Boolean = Erasure.Boxing.isBox(sym)
+ def isUnbox(sym: Symbol): Boolean = Erasure.Boxing.isUnbox(sym)
+
+ val primitives: Primitives = new Primitives {
+ val primitives = new DottyPrimitives(ctx)
+ def getPrimitive(app: Apply, reciever: Type): Int = primitives.getPrimitive(app, reciever)
+
+ def getPrimitive(sym: Symbol): Int = primitives.getPrimitive(sym)
+
+ def isPrimitive(fun: Tree): Boolean = primitives.isPrimitive(fun)
+ }
+ implicit val TypeDefTag: ClassTag[TypeDef] = ClassTag[TypeDef](classOf[TypeDef])
+ implicit val ApplyTag: ClassTag[Apply] = ClassTag[Apply](classOf[Apply])
+ implicit val SelectTag: ClassTag[Select] = ClassTag[Select](classOf[Select])
+ implicit val TypeApplyTag: ClassTag[TypeApply] = ClassTag[TypeApply](classOf[TypeApply])
+ implicit val ClassDefTag: ClassTag[ClassDef] = ClassTag[TypeDef](classOf[TypeDef])
+ implicit val TryTag: ClassTag[Try] = ClassTag[Try](classOf[Try])
+ implicit val AssignTag: ClassTag[Assign] = ClassTag[Assign](classOf[Assign])
+ implicit val IdentTag: ClassTag[Ident] = ClassTag[Ident](classOf[Ident])
+ implicit val IfTag: ClassTag[If] = ClassTag[If](classOf[If])
+ implicit val LabelDefTag: ClassTag[LabelDef] = ClassTag[LabelDef](classOf[LabelDef])
+ implicit val ValDefTag: ClassTag[ValDef] = ClassTag[ValDef](classOf[ValDef])
+ implicit val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw])
+ implicit val ReturnTag: ClassTag[Return] = ClassTag[Return](classOf[Return])
+ implicit val LiteralTag: ClassTag[Literal] = ClassTag[Literal](classOf[Literal])
+ implicit val BlockTag: ClassTag[Block] = ClassTag[Block](classOf[Block])
+ implicit val TypedTag: ClassTag[Typed] = ClassTag[Typed](classOf[Typed])
+ implicit val ArrayValueTag: ClassTag[ArrayValue] = ClassTag[ArrayValue](classOf[ArrayValue])
+ implicit val MatchTag: ClassTag[Match] = ClassTag[Match](classOf[Match])
+ implicit val CaseDefTag: ClassTag[CaseDef] = ClassTag[CaseDef](classOf[CaseDef])
+ implicit val ThisTag: ClassTag[This] = ClassTag[This](classOf[This])
+ implicit val AlternativeTag: ClassTag[Alternative] = ClassTag[Alternative](classOf[Alternative])
+ implicit val DefDefTag: ClassTag[DefDef] = ClassTag[DefDef](classOf[DefDef])
+ implicit val ModuleDefTag: ClassTag[ModuleDef] = ClassTag[ModuleDef](classOf[ModuleDef])
+ implicit val NameTag: ClassTag[Name] = ClassTag[Name](classOf[Name])
+ implicit val TemplateTag: ClassTag[Template] = ClassTag[Template](classOf[Template])
+ implicit val BindTag: ClassTag[Bind] = ClassTag[Bind](classOf[Bind])
+ implicit val NewTag: ClassTag[New] = ClassTag[New](classOf[New])
+ implicit val ApplyDynamicTag: ClassTag[ApplyDynamic] = ClassTag[ApplyDynamic](classOf[ApplyDynamic])
+ implicit val SuperTag: ClassTag[Super] = ClassTag[Super](classOf[Super])
+ implicit val ConstantClassTag: ClassTag[Constant] = ClassTag[Constant](classOf[Constant])
+ implicit val ClosureTag: ClassTag[Closure] = ClassTag[Closure](classOf[Closure])
+
+ /* dont emit any annotations for now*/
+ def isRuntimeVisible(annot: Annotation): Boolean = false
+ def shouldEmitAnnotation(annot: Annotation): Boolean = false
+
+ def emitAnnotations(cw: ClassVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
+ def emitAnnotations(mw: MethodVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
+ def emitAnnotations(fw: FieldVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
+ def emitParamAnnotations(jmethod: MethodVisitor, pannotss: List[List[Annotation]], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
+ def getAnnotPickle(jclassName: String, sym: Symbol): Option[Annotation] = None
+
+
+ def getRequiredClass(fullname: String): Symbol = ctx.requiredClass(fullname.toTermName)
+
+ def getClassIfDefined(fullname: String): Symbol = NoSymbol // used only for android. todo: implement
+
+ private def erasureString(clazz: Class[_]): String = {
+ if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]"
+ else clazz.getName
+ }
+
+ def requiredClass[T](implicit evidence: ClassTag[T]): Symbol = {
+ ctx.requiredClass(erasureString(evidence.runtimeClass).toTermName)
+ }
+
+ def requiredModule[T](implicit evidence: ClassTag[T]): Symbol = {
+ val moduleName = erasureString(evidence.runtimeClass)
+ val className = if (moduleName.endsWith("$")) moduleName.dropRight(1) else moduleName
+ ctx.requiredModule(className.toTermName)
+ }
+
+
+ def debuglog(msg: => String): Unit = ctx.debuglog(msg)
+ def informProgress(msg: String): Unit = ctx.informProgress(msg)
+ def log(msg: => String): Unit = ctx.log(msg)
+ def error(pos: Position, msg: String): Unit = ctx.error(msg, pos)
+ def warning(pos: Position, msg: String): Unit = ctx.warning(msg, pos)
+ def abort(msg: String): Nothing = {
+ ctx.error(msg)
+ throw new RuntimeException(msg)
+ }
+
+ def emitAsmp: Option[String] = None
+
+ def shouldEmitJumpAfterLabels = true
+
+ def dumpClasses: Option[String] =
+ if(ctx.settings.Ydumpclasses.isDefault) None
+ else Some(ctx.settings.Ydumpclasses.value)
+
+ def mainClass: Option[String] =
+ if (ctx.settings.mainClass.isDefault) None
+ else Some(ctx.settings.mainClass.value)
+ def setMainClass(name: String): Unit = ctx.settings.mainClass.update(name)
+
+
+ def noForwarders: Boolean = ctx.settings.noForwarders.value
+ def debuglevel: Int = 3 // 0 -> no debug info; 1-> filename; 2-> lines; 3-> varnames
+ def settings_debug: Boolean = ctx.settings.debug.value
+ def targetPlatform: String = ctx.settings.target.value
+
+ val perRunCaches: Caches = new Caches {
+ def newAnyRefMap[K <: AnyRef, V](): mutable.AnyRefMap[K, V] = new mutable.AnyRefMap[K, V]()
+ def newWeakMap[K, V](): mutable.WeakHashMap[K, V] = new mutable.WeakHashMap[K, V]()
+ def recordCache[T <: Clearable](cache: T): T = cache
+ def newWeakSet[K <: AnyRef](): WeakHashSet[K] = new WeakHashSet[K]()
+ def newMap[K, V](): mutable.HashMap[K, V] = new mutable.HashMap[K, V]()
+ def newSet[K](): mutable.Set[K] = new mutable.HashSet[K]
+ }
+
+
+
+ val MODULE_INSTANCE_FIELD: String = nme.MODULE_INSTANCE_FIELD.toString
+
+ def internalNameString(offset: Int, length: Int): String = new String(Names.chrs, offset, length)
+
+ def newTermName(prefix: String): Name = prefix.toTermName
+
+ val Flag_SYNTHETIC: Flags = Flags.Synthetic.bits
+ val Flag_METHOD: Flags = Flags.Method.bits
+ val ExcludedForwarderFlags: Flags = {
+ Flags.Specialized | Flags.Lifted | Flags.Protected | Flags.JavaStatic |
+ Flags.ExpandedName | Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro
+ }.bits
+
+
+ def isQualifierSafeToElide(qual: Tree): Boolean = tpd.isIdempotentExpr(qual)
+ def desugarIdent(i: Ident): Option[Select] = {
+ i.tpe match {
+ case TermRef(prefix: TermRef, name) =>
+ Some(tpd.ref(prefix).select(i.symbol))
+ case TermRef(prefix: ThisType, name) =>
+ Some(tpd.This(prefix.cls).select(i.symbol))
+ case _ => None
+ }
+ }
+ def getLabelDefOwners(tree: Tree): Map[Tree, List[LabelDef]] = {
+ // for each rhs of a defdef returns LabelDefs inside this DefDef
+ val res = new collection.mutable.HashMap[Tree, List[LabelDef]]()
+
+ val t = new TreeTraverser {
+ var outerRhs: Tree = tree
+
+ def traverse(tree: tpd.Tree): Unit = tree match {
+ case t: DefDef =>
+ if (t.symbol is Flags.Label)
+ res.put(outerRhs, t :: res.getOrElse(outerRhs, Nil))
+ else outerRhs = t
+ traverseChildren(t)
+ case _ => traverseChildren(tree)
+ }
+ }
+
+ t.traverse(tree)
+ res.toMap
+ }
+
+ // todo: remove
+ def isMaybeBoxed(sym: Symbol) = {
+ (sym == ObjectClass) ||
+ (sym == JavaSerializableClass) ||
+ (sym == defn.ComparableClass) ||
+ (sym derivesFrom BoxedNumberClass) ||
+ (sym derivesFrom BoxedCharacterClass) ||
+ (sym derivesFrom BoxedBooleanClass)
+ }
+
+ def getSingleOutput: Option[AbstractFile] = None // todo: implement
+
+
+ def getGenericSignature(sym: Symbol, owner: Symbol): String = null // todo: implement
+
+ def getStaticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol): String = null // todo: implement
+
+
+ def sourceFileFor(cu: CompilationUnit): String = cu.source.file.name
+
+
+
+ implicit def positionHelper(a: Position): PositionHelper = new PositionHelper {
+ def isDefined: Boolean = a.exists
+ def line: Int = sourcePos(a).line
+ def finalPosition: Position = a
+ }
+
+ implicit def constantHelper(a: Constant): ConstantHelper = new ConstantHelper {
+ def booleanValue: Boolean = a.booleanValue
+ def longValue: Long = a.longValue
+ def byteValue: Byte = a.byteValue
+ def stringValue: String = a.stringValue
+ def symbolValue: Symbol = a.symbolValue
+ def floatValue: Float = a.floatValue
+ def value: Any = a.value
+ def tag: ConstantTag = a.tag
+ def typeValue: Type = a.typeValue
+ def shortValue: Short = a.shortValue
+ def intValue: Int = a.intValue
+ def doubleValue: Double = a.doubleValue
+ def charValue: Char = a.charValue
+ }
+
+
+ implicit def treeHelper(a: Tree): TreeHelper = new TreeHelper {
+ def symbol: Symbol = a.symbol
+
+ def pos: Position = a.pos
+
+ def isEmpty: Boolean = a.isEmpty
+
+ def tpe: Type = a.tpe
+
+ def exists(pred: (Tree) => Boolean): Boolean = a.find(pred).isDefined
+ }
+
+
+ implicit def annotHelper(a: Annotation): AnnotationHelper = new AnnotationHelper {
+ def atp: Type = a.tree.tpe
+
+ def assocs: List[(Name, Object)] = ???
+
+ def symbol: Symbol = a.tree.symbol
+
+ def args: List[Tree] = ???
+ }
+
+
+ implicit def nameHelper(n: Name): NameHelper = new NameHelper {
+ def toTypeName: Name = n.toTypeName
+ def isTypeName: Boolean = n.isTypeName
+ def toTermName: Name = n.toTermName
+ def dropModule: Name = ???
+
+ def len: Int = n.length
+ def offset: Int = n.start
+ def isTermName: Boolean = n.isTermName
+ def startsWith(s: String): Boolean = n.startsWith(s)
+ }
+
+
+ implicit def symHelper(sym: Symbol): SymbolHelper = new SymbolHelper {
+ // names
+ def fullName(sep: Char): String = sym.showFullName
+ def fullName: String = sym.showFullName
+ def simpleName: Name = sym.name
+ def javaSimpleName: Name = toDenot(sym).name // addModuleSuffix(simpleName.dropLocal)
+ def javaBinaryName: Name = toDenot(sym).fullNameSeparated('/') // addModuleSuffix(fullNameInternal('/'))
+ def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString
+ def name: Name = sym.name
+ def rawname: Name = sym.name // todo ????
+
+ // types
+ def info: Type = toDenot(sym).info
+ def tpe: Type = toDenot(sym).info // todo whats the differentce between tpe and info?
+ def thisType: Type = toDenot(sym).thisType
+
+ // tests
+ def isClass: Boolean = {
+ sym.isClass && (sym.isPackageObject || !(sym is Flags.Package))
+ }
+ def isType: Boolean = sym.isType
+ def isAnonymousClass: Boolean = toDenot(sym).isAnonymousClass
+ def isConstructor: Boolean = toDenot(sym).isConstructor
+ def isAnonymousFunction: Boolean = toDenot(sym).isAnonymousFunction
+ def isMethod: Boolean = sym is Flags.Method
+ def isPublic: Boolean = sym.flags.is(Flags.EmptyFlags, Flags.Private | Flags.Protected)
+ def isSynthetic: Boolean = sym is Flags.Synthetic
+ def isPackageClass: Boolean = sym is Flags.PackageClass
+ def isModuleClass: Boolean = sym is Flags.ModuleClass
+ def isModule: Boolean = sym is Flags.Module
+ def isStrictFP: Boolean = false // todo: implement
+ def isLabel: Boolean = sym is Flags.Label
+ def hasPackageFlag: Boolean = sym is Flags.Package
+ def isImplClass: Boolean = sym is Flags.ImplClass
+ def isInterface: Boolean = (sym is Flags.PureInterface) || (sym is Flags.Trait)
+ def hasGetter: Boolean = false // used only for generaration of beaninfo todo: implement
+ def isGetter: Boolean = toDenot(sym).isGetter
+ def isSetter: Boolean = toDenot(sym).isSetter
+ def isGetClass: Boolean = sym eq defn.Any_getClass
+ def isJavaDefined: Boolean = sym is Flags.JavaDefined
+ def isJavaDefaultMethod: Boolean = !((sym is Flags.Deferred) || toDenot(sym).isClassConstructor)
+ def isDeferred: Boolean = sym is Flags.Deferred
+ def isPrivate: Boolean = sym is Flags.Private
+ def getsJavaFinalFlag: Boolean =
+ isFinal && !toDenot(sym).isClassConstructor && !(sym is Flags.Mutable) && !(sym.enclosingClass is Flags.JavaInterface)
+
+ def getsJavaPrivateFlag: Boolean =
+ isPrivate //|| (sym.isPrimaryConstructor && sym.owner.isTopLevelModuleClass)
+
+ def isFinal: Boolean = sym is Flags.Final
+ def isStaticMember: Boolean = (sym ne NoSymbol) && ((sym is Flags.JavaStatic) || (owner is Flags.ImplClass))
+ // guard against no sumbol cause this code is executed to select which call type(static\dynamic) to use to call array.clone
+
+ def isBottomClass: Boolean = (sym ne defn.NullClass) && (sym ne defn.NothingClass)
+ def isBridge: Boolean = sym is Flags.Bridge
+ def isArtifact: Boolean = sym is Flags.Artifact
+ def hasEnumFlag: Boolean = sym is Flags.Enum
+ def hasAccessBoundary: Boolean = sym.accessBoundary(defn.RootClass) ne defn.RootClass
+ def isVarargsMethod: Boolean = sym is Flags.JavaVarargs
+ def isDeprecated: Boolean = false
+ def isMutable: Boolean = sym is Flags.Mutable
+ def hasAbstractFlag: Boolean = (sym is Flags.Abstract) || (sym is Flags.JavaInterface)
+ def hasModuleFlag: Boolean = sym is Flags.Module
+ def isSynchronized: Boolean = sym is Flags.Synchronized
+ def isNonBottomSubClass(other: Symbol): Boolean = sym.derivesFrom(other)
+ def hasAnnotation(sym: Symbol): Boolean = false
+ def shouldEmitForwarders: Boolean = //exitingPickler { !(sym.name.toString contains '$')
+ (sym is Flags.Module) && !(sym is Flags.ImplClass) /// !sym.isNestedClass
+ def isJavaEntryPoint: Boolean = CollectEntryPoints.isJavaEntyPoint(sym)
+
+ def isClassConstructor: Boolean = toDenot(sym).isClassConstructor
+
+ /**
+ * 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 = sym.isStatic && (sym is Flags.Module)
+
+ def isStaticConstructor: Boolean = isStaticMember && isClassConstructor
+
+
+ // navigation
+ def owner: Symbol = toDenot(sym).owner
+ def rawowner: Symbol = owner
+ def originalOwner: Symbol = {
+ try {
+ if (sym.exists) {
+ val original = toDenot(sym).initial
+ val validity = original.validFor
+ val shiftedContext = ctx.withPhase(validity.phaseId)
+ val r = toDenot(sym)(shiftedContext).maybeOwner
+ if(r is Flags.Package) NoSymbol
+ else r
+ } else NoSymbol
+ } catch {
+ case e: NotDefinedHere => NoSymbol // todo: do we have a method to tests this?
+ }
+ }
+ def parentSymbols: List[Symbol] = toDenot(sym).info.parents.map(_.typeSymbol)
+ def superClass: Symbol = toDenot(sym).superClass
+ def enclClass: Symbol = toDenot(sym).enclosingClass
+ def linkedClassOfClass: Symbol = linkedClass
+ def linkedClass: Symbol = toDenot(sym).linkedClass //exitingPickler(sym.linkedClassOfClass)
+ def companionClass: Symbol = toDenot(sym).companionClass
+ def companionModule: Symbol = toDenot(sym).companionModule
+ def companionSymbol: Symbol = if (sym is Flags.Module) companionClass else companionModule
+ def moduleClass: Symbol = toDenot(sym).moduleClass
+ def enclosingClassSym: Symbol = enclClass //todo is handled specially for JavaDefined symbols in scalac
+
+
+
+ // members
+ def primaryConstructor: Symbol = toDenot(sym).primaryConstructor
+ def nestedClasses: List[Symbol] = memberClasses //exitingPhase(currentRun.lambdaliftPhase)(sym.memberClasses)
+ def memberClasses: List[Symbol] = toDenot(sym).info.memberClasses.map(_.symbol).toList
+ def annotations: List[Annotation] = Nil
+ 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
+ }
+ def fieldSymbols: List[Symbol] = toDenot(sym).info.memberClasses.map(_.symbol).toList
+ def methodSymbols: List[Symbol] =
+ for (f <- toDenot(sym).info.decls.toList if !f.isMethod && f.isTerm && !f.isModule) yield f
+ def serialVUID: Option[Long] = None
+
+
+ def freshLocal(cunit: CompilationUnit, name: String, tpe: Type, pos: Position, flags: Flags): Symbol = {
+ ctx.newSymbol(sym, name.toTermName, FlagSet(flags), tpe, NoSymbol, pos)
+ }
+
+ def getter(clz: Symbol): Symbol = decorateSymbol(sym).getter
+ def setter(clz: Symbol): Symbol = decorateSymbol(sym).setter
+
+ def moduleSuffix: String = "" // todo: validate that names already have $ suffix
+ def outputDirectory: AbstractFile = new PlainDirectory(new Directory(new JFile(ctx.settings.d.value)))
+ def pos: Position = sym.pos
+
+ def throwsAnnotations: List[Symbol] = Nil
+
+ /**
+ * All interfaces implemented by a class, except for those inherited through the superclass.
+ *
+ */
+ def superInterfaces: List[Symbol] = decorateSymbol(sym).superInterfaces
+
+ /**
+ * True for module classes of package level objects. The backend will generate a mirror class for
+ * such objects.
+ */
+ def isTopLevelModuleClass: Boolean = sym.isModuleClass && sym.isStatic
+
+ /**
+ * 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.isStatic
+
+
+ def addRemoteRemoteExceptionAnnotation: Unit = ()
+ }
+
+
+ implicit def typeHelper(tp: Type): TypeHelper = new TypeHelper {
+ def member(string: Name): Symbol = tp.member(string.toTermName).symbol
+
+ def isFinalType: Boolean = tp.typeSymbol is Flags.Final //in scalac checks for type parameters. Why? Aren't they gone by backend?
+
+ def underlying: Type = tp match {
+ case t: TypeProxy => t.underlying
+ case _ => tp
+ }
+
+ def paramTypes: List[Type] = tp.firstParamTypes
+
+ def <:<(other: Type): Boolean = tp <:< other
+
+ def memberInfo(s: Symbol): Type = tp.memberInfo(s)
+
+ def decls: List[Symbol] = tp.decls.map(_.symbol).toList
+
+ def members: List[Symbol] =
+ tp.memberDenots(takeAllFilter, (name, buf) => buf ++= member(name).alternatives).map(_.symbol).toList
+
+ def typeSymbol: Symbol = tp.widenDealias.typeSymbol
+
+ def =:=(other: Type): Boolean = tp =:= other
+
+ def membersBasedOnFlags(excludedFlags: Flags, requiredFlags: Flags): List[Symbol] =
+ tp.membersBasedOnFlags(FlagSet(requiredFlags), FlagSet(excludedFlags)).map(_.symbol).toList
+
+ def resultType: Type = tp.resultType
+
+ def toTypeKind(ct: BCodeHelpers)(storage: ct.BCInnerClassGen): ct.bTypes.BType = {
+ import ct.bTypes._
+ val defn = ctx.definitions
+ import coreBTypes._
+ import Types._
+ /**
+ * 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[ct.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
+ }
+
+ tp.widenDealias match {
+ case JavaArrayType(el) =>ArrayBType(el.toTypeKind(ct)(storage)) // Array type such as Array[Int] (kept by erasure)
+ case t: TypeRef =>
+ t.info match {
+
+ case _ =>
+ if(!t.symbol.isClass) nonClassTypeRefToBType(t.symbol) // See comment on nonClassTypeRefToBType
+ else primitiveOrClassToBType(t.symbol) // Common reference to a type such as scala.Int or java.lang.String
+ }
+ case Types.ClassInfo(_, sym, _, _, _) => primitiveOrClassToBType(sym) // We get here, for example, for genLoadModule, which invokes toTypeKind(moduleClassSymbol.info)
+
+ case t: MethodType => // triggers for LabelDefs
+ t.resultType.toTypeKind(ct)(storage)
+
+ /* 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(ct)(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 =>
+ ctx.warning(
+ 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[ct.int.Symbol])
+ // case t: SingletonType => primitiveOrClassToBType(t.classSymbol)
+ case t: SingletonType => t.underlying.toTypeKind(ct)(storage)
+ case t: RefinedType => t.parent.toTypeKind(ct)(storage) //parents.map(_.toTypeKind(ct)(storage).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b))
+ }
+ }
+ }
+
+ def summaryString: String = tp.showSummary
+
+ def params: List[Symbol] = Nil // used only for emmiting annotations
+
+ def parents: List[Type] = tp.parents
+ }
+
+
+
+ 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 ApplyDynamic extends ApplyDynamicDeconstructor {
+ def _1: Tree = ???
+ def _2: List[Tree] = ???
+ }
+
+ // todo: this product1s should also eventually become name-based pattn matching
+ object Literal extends LiteralDeconstructor {
+ def get = field.const
+ }
+
+ object Throw extends ThrowDeconstructor {
+ def get = field.expr
+ }
+
+ object New extends NewDeconstructor {
+ def get = field.tpt.tpe
+ }
+
+ object This extends ThisDeconstructor {
+ def get = field.qual
+ def apply(s: Symbol): This = tpd.This(s.asClass)
+ }
+
+ object Return extends ReturnDeconstructor {
+ def get = field.expr
+ }
+
+ object Ident extends IdentDeconstructor {
+ def get = field.name
+ }
+
+ object Alternative extends AlternativeDeconstructor {
+ def get = field.trees
+ }
+
+ object Constant extends ConstantDeconstructor {
+ def get = field.value
+ }
+ object ThrownException extends ThrownException {
+ def unapply(a: Annotation): Option[Symbol] = None // todo
+ }
+
+ object Try extends TryDeconstructor {
+ def _1: Tree = field.expr
+ def _2: List[Tree] = field.cases
+ def _3: Tree = field.finalizer
+ }
+
+ object LabelDef extends LabelDeconstructor {
+ def _1: Name = field.name
+ def _2: List[Symbol] = field.vparamss.flatMap(_.map(_.symbol))
+ def _3: Tree = field.rhs
+
+ override def unapply(s: LabelDef): DottyBackendInterface.this.LabelDef.type = {
+ if(s.symbol is Flags.Label) this.field = s
+ else this.field = null
+ this
+ }
+ }
+
+ 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: Type = field.tpe match {
+ case JavaArrayType(elem) => elem
+ case _ =>
+ ctx.error(s"JavaSeqArray with type ${field.tpe} reached backend: $field", field.pos)
+ ErrorType
+ }
+ 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 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 = ???
+ def _2: Name = ???
+ def _3: Tree = ???
+ }
+
+ object Template extends TemplateDeconstructor {
+ def _1: List[Tree] = field.parents
+ def _2: ValDef = field.self
+ def _3: List[Tree] = field.constr :: 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.rhs.asInstanceOf[Template]
+ def _3: List[TypeDef] = Nil
+ }
+
+ object Closure extends ClosureDeconstructor {
+ def _1 = field.env
+ def _2 = field.meth
+ def _3 = {
+ val t = field.tpt.tpe.typeSymbol
+ if(t.exists) t
+ else {
+ val arity = field.meth.tpe.widenDealias.paramTypes.size - _1.size
+ val returnsUnit = field.meth.tpe.widenDealias.resultType.classSymbol == UnitClass
+ if(returnsUnit)
+ ctx.requiredClass(("scala.compat.java8.JProcedure"+arity).toTermName)
+ else ctx.requiredClass(("scala.compat.java8.JFunction"+arity).toTermName)
+ }
+ }
+ }
+
+ def currentUnit = ctx.compilationUnit
+} \ No newline at end of file
diff --git a/src/dotty/tools/backend/jvm/GenBCode.scala b/src/dotty/tools/backend/jvm/GenBCode.scala
new file mode 100644
index 000000000..a53e910ae
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/GenBCode.scala
@@ -0,0 +1,390 @@
+package dotty.tools.backend.jvm
+
+import dotty.tools.dotc.CompilationUnit
+import dotty.tools.dotc.ast.Trees.{ValDef, PackageDef}
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Phases.Phase
+
+import scala.collection.mutable
+import scala.tools.asm.{ClassVisitor, MethodVisitor, FieldVisitor}
+import scala.tools.nsc.Settings
+import scala.tools.nsc.backend.jvm._
+import dotty.tools.dotc
+import dotty.tools.dotc.backend.jvm.DottyPrimitives
+import dotty.tools.dotc.transform.Erasure
+
+import scala.reflect.ClassTag
+import dotty.tools.dotc.core._
+import Periods._
+import SymDenotations._
+import Contexts._
+import Types._
+import Symbols._
+import Denotations._
+import Phases._
+import java.lang.AssertionError
+import scala.tools.asm
+import scala.tools.asm.tree._
+import dotty.tools.dotc.util.{Positions, DotClass}
+import tpd._
+
+import scala.tools.nsc.backend.jvm.opt.LocalOpt
+
+class GenBCode extends Phase {
+ def phaseName: String = "genBCode"
+ private val entryPoints = new mutable.HashSet[Symbol]()
+ def registerEntryPoint(sym: Symbol) = entryPoints += sym
+
+
+ def run(implicit ctx: Context): Unit = {
+ new GenBCodePipeline(entryPoints.toList, new DottyBackendInterface()(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
+ entryPoints.clear()
+ }
+}
+
+class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInterface)(implicit val ctx: Context) extends BCodeSyncAndTry{
+
+ var tree: Tree = _
+
+ final class PlainClassBuilder(cunit: CompilationUnit) extends SyncAndTryBuilder(cunit)
+
+
+// class BCodePhase() {
+
+ private var bytecodeWriter : BytecodeWriter = null
+ private var mirrorCodeGen : JMirrorBuilder = null
+ private var beanInfoCodeGen : JBeanInfoBuilder = null
+
+ /* ---------------- q1 ---------------- */
+
+ case class Item1(arrivalPos: Int, cd: TypeDef, cunit: CompilationUnit) {
+ def isPoison = { arrivalPos == Int.MaxValue }
+ }
+ private val poison1 = Item1(Int.MaxValue, null, ctx.compilationUnit)
+ private val q1 = new java.util.LinkedList[Item1]
+
+ /* ---------------- q2 ---------------- */
+
+ case class Item2(arrivalPos: Int,
+ mirror: asm.tree.ClassNode,
+ plain: asm.tree.ClassNode,
+ bean: asm.tree.ClassNode,
+ outFolder: scala.tools.nsc.io.AbstractFile) {
+ def isPoison = { arrivalPos == Int.MaxValue }
+ }
+
+ private val poison2 = Item2(Int.MaxValue, null, null, null, null)
+ private val q2 = new _root_.java.util.LinkedList[Item2]
+
+ /* ---------------- q3 ---------------- */
+
+ /*
+ * An item of queue-3 (the last queue before serializing to disk) contains three of these
+ * (one for each of mirror, plain, and bean classes).
+ *
+ * @param jclassName internal name of the class
+ * @param jclassBytes bytecode emitted for the class SubItem3 represents
+ */
+ case class SubItem3(
+ jclassName: String,
+ jclassBytes: Array[Byte]
+ )
+
+ case class Item3(arrivalPos: Int,
+ mirror: SubItem3,
+ plain: SubItem3,
+ bean: SubItem3,
+ outFolder: scala.tools.nsc.io.AbstractFile) {
+
+ def isPoison = { arrivalPos == Int.MaxValue }
+ }
+ private val i3comparator = new java.util.Comparator[Item3] {
+ override def compare(a: Item3, b: Item3) = {
+ if (a.arrivalPos < b.arrivalPos) -1
+ else if (a.arrivalPos == b.arrivalPos) 0
+ else 1
+ }
+ }
+ private val poison3 = Item3(Int.MaxValue, null, null, null, null)
+ private val q3 = new java.util.PriorityQueue[Item3](1000, i3comparator)
+
+ /*
+ * Pipeline that takes ClassDefs from queue-1, lowers them into an intermediate form, placing them on queue-2
+ */
+ class Worker1(needsOutFolder: Boolean) {
+
+ val caseInsensitively = scala.collection.mutable.Map.empty[String, Symbol]
+
+ def run() {
+ while (true) {
+ val item = q1.poll
+ if (item.isPoison) {
+ q2 add poison2
+ return
+ }
+ else {
+ try { /*withCurrentUnit(item.cunit)*/(visit(item)) }
+ catch {
+ case ex: Throwable =>
+ ex.printStackTrace()
+ ctx.error(s"Error while emitting ${int.sourceFileFor(item.cunit)}\n${ex.getMessage}")
+ }
+ }
+ }
+ }
+
+ /*
+ * Checks for duplicate internal names case-insensitively,
+ * builds ASM ClassNodes for mirror, plain, and bean classes;
+ * enqueues them in queue-2.
+ *
+ */
+ def visit(item: Item1) {
+ val Item1(arrivalPos, cd, cunit) = item
+ val claszSymbol = cd.symbol
+
+ // GenASM checks this before classfiles are emitted, https://github.com/scala/scala/commit/e4d1d930693ac75d8eb64c2c3c69f2fc22bec739
+ // todo: add back those checks
+ /*val lowercaseJavaClassName = claszSymbol.javaClassName.toLowerCase
+ caseInsensitively.get(lowercaseJavaClassName) match {
+ case None =>
+ caseInsensitively.put(lowercaseJavaClassName, claszSymbol)
+ case Some(dupClassSym) =>
+ reporter.warning(
+ claszSymbol.pos,
+ s"Class ${claszSymbol.javaClassName} differs only in case from ${dupClassSym.javaClassName}. " +
+ "Such classes will overwrite one another on case-insensitive filesystems."
+ )
+ }*/
+
+ // -------------- mirror class, if needed --------------
+ val mirrorC =
+ if (int.symHelper(claszSymbol).isTopLevelModuleClass) {
+ if (claszSymbol.companionClass == NoSymbol) {
+ mirrorCodeGen.genMirrorClass(claszSymbol, cunit)
+ } else {
+ ctx.log(s"No mirror class for module with linked class: ${claszSymbol.fullName}")
+ null
+ }
+ } else null
+
+ // -------------- "plain" class --------------
+ val pcb = new PlainClassBuilder(cunit)
+ pcb.genPlainClass(cd)
+ val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName) else null;
+ val plainC = pcb.cnode
+
+ // -------------- bean info class, if needed --------------
+ val beanC =
+ if (claszSymbol hasAnnotation int.BeanInfoAttr) {
+ beanInfoCodeGen.genBeanInfoClass(
+ claszSymbol, cunit,
+ int.symHelper(claszSymbol).fieldSymbols,
+ int.symHelper(claszSymbol).methodSymbols
+ )
+ } else null
+
+ // ----------- hand over to pipeline-2
+
+ val item2 =
+ Item2(arrivalPos,
+ mirrorC, plainC, beanC,
+ outF)
+
+ q2 add item2 // at the very end of this method so that no Worker2 thread starts mutating before we're done.
+
+ } // end of method visit(Item1)
+
+ } // end of class BCodePhase.Worker1
+
+ /*
+ * Pipeline that takes ClassNodes from queue-2. The unit of work depends on the optimization level:
+ *
+ * (a) no optimization involves:
+ * - converting the plain ClassNode to byte array and placing it on queue-3
+ */
+ class Worker2 {
+ lazy val localOpt = new LocalOpt(new Settings())
+
+ def localOptimizations(classNode: ClassNode): Unit = {
+ /*BackendStats.timed(BackendStats.methodOptTimer)*/(localOpt.methodOptimizations(classNode))
+ }
+
+ def run() {
+ while (true) {
+ val item = q2.poll
+ if (item.isPoison) {
+ q3 add poison3
+ return
+ }
+ else {
+ try {
+ localOptimizations(item.plain)
+ addToQ3(item)
+ } catch {
+ case ex: Throwable =>
+ ex.printStackTrace()
+ ctx.error(s"Error while emitting ${item.plain.name}\n${ex.getMessage}")
+ }
+ }
+ }
+ }
+
+ private def addToQ3(item: Item2) {
+
+ def getByteArray(cn: asm.tree.ClassNode): Array[Byte] = {
+ val cw = new CClassWriter(extraProc)
+ cn.accept(cw)
+ cw.toByteArray
+ }
+
+ val Item2(arrivalPos, mirror, plain, bean, outFolder) = item
+
+ val mirrorC = if (mirror == null) null else SubItem3(mirror.name, getByteArray(mirror))
+ val plainC = SubItem3(plain.name, getByteArray(plain))
+ val beanC = if (bean == null) null else SubItem3(bean.name, getByteArray(bean))
+
+ if (AsmUtils.traceSerializedClassEnabled && plain.name.contains(AsmUtils.traceSerializedClassPattern)) {
+ if (mirrorC != null) AsmUtils.traceClass(mirrorC.jclassBytes)
+ AsmUtils.traceClass(plainC.jclassBytes)
+ if (beanC != null) AsmUtils.traceClass(beanC.jclassBytes)
+ }
+
+ q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder)
+
+ }
+
+ } // end of class BCodePhase.Worker2
+
+ var arrivalPos = 0
+
+ /*
+ * A run of the BCodePhase phase comprises:
+ *
+ * (a) set-up steps (most notably supporting maps in `BCodeTypes`,
+ * but also "the" writer where class files in byte-array form go)
+ *
+ * (b) building of ASM ClassNodes, their optimization and serialization.
+ *
+ * (c) tear down (closing the classfile-writer and clearing maps)
+ *
+ */
+ def run(t: Tree) {
+ this.tree = t
+
+ // val bcodeStart = Statistics.startTimer(BackendStats.bcodeTimer)
+
+ // val initStart = Statistics.startTimer(BackendStats.bcodeInitTimer)
+ arrivalPos = 0 // just in case
+ // scalaPrimitives.init()
+ bTypes.intializeCoreBTypes()
+ // Statistics.stopTimer(BackendStats.bcodeInitTimer, initStart)
+
+ // initBytecodeWriter invokes fullName, thus we have to run it before the typer-dependent thread is activated.
+ bytecodeWriter = initBytecodeWriter(entryPoints)
+ mirrorCodeGen = new JMirrorBuilder
+ beanInfoCodeGen = new JBeanInfoBuilder
+
+ val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter]
+ buildAndSendToDisk(needsOutfileForSymbol)
+
+ // closing output files.
+ bytecodeWriter.close()
+ // Statistics.stopTimer(BackendStats.bcodeTimer, bcodeStart)
+
+ /* TODO Bytecode can be verified (now that all classfiles have been written to disk)
+ *
+ * (1) asm.util.CheckAdapter.verify()
+ * public static void verify(ClassReader cr, ClassLoader loader, boolean dump, PrintWriter pw)
+ * passing a custom ClassLoader to verify inter-dependent classes.
+ * Alternatively,
+ * - an offline-bytecode verifier could be used (e.g. Maxine brings one as separate tool).
+ * - -Xverify:all
+ *
+ * (2) if requested, check-java-signatures, over and beyond the syntactic checks in `getGenericSignature()`
+ *
+ */
+ }
+
+ /*
+ * Sequentially:
+ * (a) place all ClassDefs in queue-1
+ * (b) dequeue one at a time from queue-1, convert it to ASM ClassNode, place in queue-2
+ * (c) dequeue one at a time from queue-2, convert it to byte-array, place in queue-3
+ * (d) serialize to disk by draining queue-3.
+ */
+ private def buildAndSendToDisk(needsOutFolder: Boolean) {
+
+ feedPipeline1()
+ // val genStart = Statistics.startTimer(BackendStats.bcodeGenStat)
+ (new Worker1(needsOutFolder)).run()
+ // Statistics.stopTimer(BackendStats.bcodeGenStat, genStart)
+
+ (new Worker2).run()
+
+ // val writeStart = Statistics.startTimer(BackendStats.bcodeWriteTimer)
+ drainQ3()
+ // Statistics.stopTimer(BackendStats.bcodeWriteTimer, writeStart)
+
+ }
+
+ /* Feed pipeline-1: place all ClassDefs on q1, recording their arrival position. */
+ private def feedPipeline1() {
+ def gen(tree: Tree) {
+ tree match {
+ case EmptyTree => ()
+ case PackageDef(_, stats) => stats foreach gen
+ case ValDef(name, tpt, rhs) => () // module val not emmited
+ case cd: TypeDef =>
+ q1 add Item1(arrivalPos, cd, int.currentUnit)
+ arrivalPos += 1
+ }
+ }
+ gen(tree)
+ q1 add poison1
+ }
+
+ /* Pipeline that writes classfile representations to disk. */
+ private def drainQ3() {
+
+ def sendToDisk(cfr: SubItem3, outFolder: scala.tools.nsc.io.AbstractFile) {
+ if (cfr != null){
+ val SubItem3(jclassName, jclassBytes) = cfr
+ try {
+ val outFile =
+ if (outFolder == null) null
+ else getFileForClassfile(outFolder, jclassName, ".class")
+ bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, outFile)
+ }
+ catch {
+ case e: FileConflictException =>
+ ctx.error(s"error writing $jclassName: ${e.getMessage}")
+ }
+ }
+ }
+
+ var moreComing = true
+ // `expected` denotes the arrivalPos whose Item3 should be serialized next
+ var expected = 0
+
+ while (moreComing) {
+ val incoming = q3.poll
+ moreComing = !incoming.isPoison
+ if (moreComing) {
+ val item = incoming
+ val outFolder = item.outFolder
+ sendToDisk(item.mirror, outFolder)
+ sendToDisk(item.plain, outFolder)
+ sendToDisk(item.bean, outFolder)
+ expected += 1
+ }
+ }
+
+ // we're done
+ assert(q1.isEmpty, s"Some ClassDefs remained in the first queue: $q1")
+ assert(q2.isEmpty, s"Some classfiles remained in the second queue: $q2")
+ assert(q3.isEmpty, s"Some classfiles weren't written to disk: $q3")
+
+ }
+ //} // end of class BCodePhase
+}
diff --git a/src/dotty/tools/backend/jvm/LabelDefs.scala b/src/dotty/tools/backend/jvm/LabelDefs.scala
new file mode 100644
index 000000000..0e50e9366
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/LabelDefs.scala
@@ -0,0 +1,185 @@
+package dotty.tools.backend.jvm
+
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Types
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, MiniPhase, MiniPhaseTransform}
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc
+import dotty.tools.dotc.backend.jvm.DottyPrimitives
+import dotty.tools.dotc.core.Flags.FlagSet
+import dotty.tools.dotc.transform.Erasure
+import dotty.tools.dotc.transform.SymUtils._
+import java.io.{File => JFile}
+
+import scala.collection.generic.Clearable
+import scala.collection.mutable
+import scala.collection.mutable.{ListBuffer, ArrayBuffer}
+import scala.reflect.ClassTag
+import scala.reflect.internal.util.WeakHashSet
+import scala.reflect.io.{Directory, PlainDirectory, AbstractFile}
+import scala.tools.asm.{ClassVisitor, FieldVisitor, MethodVisitor}
+import scala.tools.nsc.backend.jvm.{BCodeHelpers, BackendInterface}
+import dotty.tools.dotc.core._
+import Periods._
+import SymDenotations._
+import Contexts._
+import Types._
+import Symbols._
+import Denotations._
+import Phases._
+import java.lang.AssertionError
+import dotty.tools.dotc.util.Positions.Position
+import Decorators._
+import tpd._
+import StdNames.nme
+
+/**
+ * Verifies that each Label DefDef has only a single address to jump back and
+ * reorders them such that they are not nested and this address is a fall-through address for JVM
+ *
+ * ei such code
+ *
+ *
+ * <label> def foo(i: Int) = {
+ * <label> def bar = 0
+ * <label> def dough(i: Int) = if(i == 0) bar else foo(i-1)
+ * dough(i)
+ * }
+ *
+ * foo(100)
+ *
+ * will get rewritten to
+ *
+ * \
+ * <label> def foo(i: Int) = dough(i)
+ * <label> def dough(i: Int) = if(i == 0) bar else foo(i-1)
+ * <label> def bar = 2
+ * foo(100)
+ *
+ * Proposed way to generate this pattern in backend is:
+ *
+ * foo(100)
+ * <jump foo>
+ * <label> def foo(i: Int) = dough(i)
+ * // <jump a> // unreachable
+ * <label> def dough(i: Int) = if(i == 0) bar else foo(i-1)
+ * // <jump a> // unreachable
+ * <label> def bar = 2
+ * // <jump a> // unreachable
+ * <asm point a>
+ *
+ * Unreachable jumps will be eliminated by local dead code analysis.
+ * After JVM is smart enough to remove next-line jumps
+ *
+ * Note that Label DefDefs can be only nested in Block, otherwise no one would be able to call them
+ * Other DefDefs are eliminated
+ */
+class LabelDefs extends MiniPhaseTransform {
+ def phaseName: String = "labelDef"
+
+ val queue = new ArrayBuffer[Tree]()
+
+
+
+ override def transformBlock(tree: tpd.Block)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ collectLabelDefs.clear
+ val newStats = collectLabelDefs.transformStats(tree.stats)
+ val newExpr = collectLabelDefs.transform(tree.expr)
+ val labelCalls = collectLabelDefs.labelCalls
+ val entryPoints = collectLabelDefs.parentLabelCalls
+ val labelDefs = collectLabelDefs.labelDefs
+
+ // make sure that for every label there's a single location it should return and single entry point
+ // if theres already a location that it returns to that's a failure
+ val disallowed = new mutable.HashMap[Symbol, Tree]()
+ queue.sizeHint(labelCalls.size + entryPoints.size)
+ def moveLabels(entryPoint: Tree): List[Tree] = {
+ if((entryPoint.symbol is Flags.Label) && labelDefs.contains(entryPoint.symbol)) {
+ val visitedNow = new mutable.HashMap[Symbol, Tree]()
+ val treesToAppend = new ArrayBuffer[Tree]() // order matters. parents should go first
+ queue.clear()
+
+ var visited = 0
+ queue += entryPoint
+ while (visited < queue.size) {
+ val owningLabelDefSym = queue(visited).symbol
+ val owningLabelDef = labelDefs(owningLabelDefSym)
+ for (call <- labelCalls(owningLabelDefSym))
+ if (disallowed.contains(call.symbol)) {
+ val oldCall = disallowed(call.symbol)
+ ctx.error(s"Multiple return locations for Label $oldCall and $call", call.symbol.pos)
+ } else {
+ if ((!visitedNow.contains(call.symbol)) && labelDefs.contains(call.symbol)) {
+ val df = labelDefs(call.symbol)
+ visitedNow.put(call.symbol, labelDefs(call.symbol))
+ queue += call
+ }
+ }
+ if(!treesToAppend.contains(owningLabelDef))
+ treesToAppend += owningLabelDef
+ visited += 1
+ }
+ disallowed ++= visitedNow
+
+ treesToAppend.toList
+ } else Nil
+ }
+
+ cpy.Block(tree)(entryPoints.flatMap(moveLabels).toList ++ newStats, newExpr)
+
+ }
+
+ val collectLabelDefs = new TreeMap() {
+
+ // label calls from this DefDef
+ var parentLabelCalls: mutable.Set[Tree] = new mutable.HashSet[Tree]()
+ var isInsideLabel = false
+ var isInsideBlock = false
+
+ def shouldMoveLabel = !isInsideBlock
+
+ // labelSymbol -> Defining tree
+ val labelDefs = new mutable.HashMap[Symbol, Tree]()
+ // owner -> all calls by this owner
+ val labelCalls = new mutable.HashMap[Symbol, mutable.Set[Tree]]()
+ val labelCallCounts = new mutable.HashMap[Symbol, Int]()
+
+ def clear = {
+ parentLabelCalls.clear()
+ labelDefs.clear()
+ labelCalls.clear()
+ }
+
+ override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
+ case t: Template => t
+ case t: Block =>
+ val tmp = isInsideBlock
+ isInsideBlock = true
+ val r = super.transform(t)
+ isInsideBlock = tmp
+ r
+ case t: DefDef =>
+ assert(t.symbol is Flags.Label)
+ val st = parentLabelCalls
+ parentLabelCalls = new mutable.HashSet[Tree]()
+ val tmp = isInsideLabel
+ isInsideLabel = true
+ val r = super.transform(tree)
+ isInsideLabel = tmp
+ labelCalls(r.symbol) = parentLabelCalls
+ parentLabelCalls = st
+ if(shouldMoveLabel) {
+ labelDefs(r.symbol) = r
+ EmptyTree
+ } else r
+ case t: Apply if t.symbol is Flags.Label =>
+ parentLabelCalls = parentLabelCalls + t
+ labelCallCounts.get(t.symbol)
+ super.transform(tree)
+ case _ =>
+ super.transform(tree)
+
+ }
+ }
+}
diff --git a/src/dotty/tools/backend/jvm/scalaPrimitives.scala b/src/dotty/tools/backend/jvm/scalaPrimitives.scala
new file mode 100755
index 000000000..857a92d21
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/scalaPrimitives.scala
@@ -0,0 +1,417 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2012 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package dotty.tools.dotc
+package backend.jvm
+
+import dotty.tools.backend.jvm.GenBCodePipeline
+import dotty.tools.dotc.ast.Trees.Select
+import dotty.tools.dotc.ast.tpd._
+import dotty.tools.dotc.core.Names.TermName
+import dotty.tools.dotc.core.StdNames
+import dotty.tools.dotc.core.StdNames._
+import dotty.tools.dotc.core.Types.{JavaArrayType, ErrorType, Type}
+
+import scala.collection.{ mutable, immutable }
+
+import core.Contexts.Context
+import core.Symbols.{Symbol, NoSymbol}
+
+/** Scala primitive operations are represented as methods in `Any` and
+ * `AnyVal` subclasses. Here we demultiplex them by providing a mapping
+ * from their symbols to integers. Different methods exist for
+ * different value types, but with the same meaning (like plus, minus,
+ * etc.). They will all be mapped to the same int.
+ *
+ * Note: The three equal methods have the following semantics:
+ * - `"=="` checks for `null`, and if non-null, calls
+ * `java.lang.Object.equals`
+ * `(class: Any; modifier: final)`. Primitive: `EQ`
+ * - `"eq"` usual reference comparison
+ * `(class: AnyRef; modifier: final)`. Primitive: `ID`
+ * - `"equals"` user-defined equality (Java semantics)
+ * `(class: Object; modifier: none)`. Primitive: `EQUALS`
+ *
+ * Inspired from the `scalac` compiler.
+ */
+class DottyPrimitives(ctx: Context) {
+ import scala.tools.nsc.backend.ScalaPrimitives._
+
+ private lazy val primitives: immutable.Map[Symbol, Int] = init
+
+ /** Return the code for the given symbol. */
+ def getPrimitive(sym: Symbol): Int = {
+ primitives(sym)
+ }
+
+ /**
+ * Return the primitive code of the given operation. If the
+ * operation is an array get/set, we inspect the type of the receiver
+ * to demux the operation.
+ *
+ * @param fun The method symbol
+ * @param tpe The type of the receiver object. It is used only for array
+ * operations
+ */
+ def getPrimitive(app: Apply, tpe: Type)(implicit ctx: Context): Int = {
+ val fun = app.fun.symbol
+ val defn = ctx.definitions
+ val code = app.fun match {
+ case Select(_, nme.primitive.arrayLength) =>
+ LENGTH
+ case Select(_, nme.primitive.arrayUpdate) =>
+ UPDATE
+ case Select(_, nme.primitive.arrayApply) =>
+ APPLY
+ case _ => getPrimitive(fun)
+ }
+
+ def elementType: Type = tpe.widenDealias match {
+ case defn.ArrayType(el) => el
+ case JavaArrayType(el) => el
+ case _ =>
+ ctx.error(s"expected Array $tpe")
+ ErrorType
+ }
+
+ code match {
+
+ case APPLY =>
+ elementType.classSymbol match {
+ case defn.BooleanClass => ZARRAY_GET
+ case defn.ByteClass => BARRAY_GET
+ case defn.ShortClass => SARRAY_GET
+ case defn.CharClass => CARRAY_GET
+ case defn.IntClass => IARRAY_GET
+ case defn.LongClass => LARRAY_GET
+ case defn.FloatClass => FARRAY_GET
+ case defn.DoubleClass => DARRAY_GET
+ case _ => OARRAY_GET
+ }
+
+ case UPDATE =>
+ elementType.classSymbol match {
+ case defn.BooleanClass => ZARRAY_SET
+ case defn.ByteClass => BARRAY_SET
+ case defn.ShortClass => SARRAY_SET
+ case defn.CharClass => CARRAY_SET
+ case defn.IntClass => IARRAY_SET
+ case defn.LongClass => LARRAY_SET
+ case defn.FloatClass => FARRAY_SET
+ case defn.DoubleClass => DARRAY_SET
+ case _ => OARRAY_SET
+ }
+
+ case LENGTH =>
+ elementType.classSymbol match {
+ case defn.BooleanClass => ZARRAY_LENGTH
+ case defn.ByteClass => BARRAY_LENGTH
+ case defn.ShortClass => SARRAY_LENGTH
+ case defn.CharClass => CARRAY_LENGTH
+ case defn.IntClass => IARRAY_LENGTH
+ case defn.LongClass => LARRAY_LENGTH
+ case defn.FloatClass => FARRAY_LENGTH
+ case defn.DoubleClass => DARRAY_LENGTH
+ case _ => OARRAY_LENGTH
+ }
+
+ case _ =>
+ code
+ }
+ }
+
+ /** Initialize the primitive map */
+ private def init: immutable.Map[Symbol, Int] = {
+
+ implicit val ctx = this.ctx
+
+ import core.Symbols.defn
+ val primitives = new mutable.HashMap[Symbol, Int]()
+
+ /** Add a primitive operation to the map */
+ def addPrimitive(s: Symbol, code: Int): Unit = {
+ assert(!(primitives contains s), "Duplicate primitive " + s)
+ primitives(s) = code
+ }
+
+ def addPrimitives(cls: Symbol, method: TermName, code: Int)(implicit ctx: Context): Unit = {
+ val alts = cls.info.member(method).alternatives.map(_.symbol)
+ if (alts.isEmpty)
+ ctx.error(s"Unknown primitive method $cls.$method")
+ else alts foreach (s =>
+ addPrimitive(s,
+ s.info.paramTypess match {
+ case List(tp :: _) if code == ADD && tp =:= ctx.definitions.StringType => CONCAT
+ case _ => code
+ }
+ )
+ )
+ }
+
+ // scala.Any
+ addPrimitive(defn.Any_==, EQ)
+ addPrimitive(defn.Any_!=, NE)
+ addPrimitive(defn.Any_isInstanceOf, IS)
+ addPrimitive(defn.Any_asInstanceOf, AS)
+ addPrimitive(defn.Any_##, HASH)
+
+ // java.lang.Object
+ addPrimitive(defn.Object_eq, ID)
+ addPrimitive(defn.Object_ne, NI)
+ /* addPrimitive(defn.Any_==, EQ)
+ addPrimitive(defn.Any_!=, NE)*/
+ addPrimitive(defn.Object_synchronized, SYNCHRONIZED)
+ /*addPrimitive(defn.Any_isInstanceOf, IS)
+ addPrimitive(defn.Any_asInstanceOf, AS)*/
+
+ // java.lang.String
+ addPrimitive(defn.String_+, CONCAT)
+
+ import core.StdNames.nme
+
+ // scala.Array
+ lazy val ArrayClass = defn.ArrayClass
+ addPrimitives(ArrayClass, nme.length, LENGTH)
+ addPrimitives(ArrayClass, nme.apply, APPLY)
+ addPrimitives(ArrayClass, nme.update, UPDATE)
+
+ // scala.Boolean
+ lazy val BooleanClass = defn.BooleanClass
+ addPrimitives(BooleanClass, nme.EQ, EQ)
+ addPrimitives(BooleanClass, nme.NE, NE)
+ addPrimitives(BooleanClass, nme.UNARY_!, ZNOT)
+ addPrimitives(BooleanClass, nme.ZOR, ZOR)
+ addPrimitives(BooleanClass, nme.ZAND, ZAND)
+ addPrimitives(BooleanClass, nme.OR, OR)
+ addPrimitives(BooleanClass, nme.AND, AND)
+ addPrimitives(BooleanClass, nme.XOR, XOR)
+
+ // scala.Byte
+ lazy val ByteClass = defn.ByteClass
+ addPrimitives(ByteClass, nme.EQ, EQ)
+ addPrimitives(ByteClass, nme.NE, NE)
+ addPrimitives(ByteClass, nme.ADD, ADD)
+ addPrimitives(ByteClass, nme.SUB, SUB)
+ addPrimitives(ByteClass, nme.MUL, MUL)
+ addPrimitives(ByteClass, nme.DIV, DIV)
+ addPrimitives(ByteClass, nme.MOD, MOD)
+ addPrimitives(ByteClass, nme.LT, LT)
+ addPrimitives(ByteClass, nme.LE, LE)
+ addPrimitives(ByteClass, nme.GT, GT)
+ addPrimitives(ByteClass, nme.GE, GE)
+ addPrimitives(ByteClass, nme.XOR, XOR)
+ addPrimitives(ByteClass, nme.OR, OR)
+ addPrimitives(ByteClass, nme.AND, AND)
+ addPrimitives(ByteClass, nme.LSL, LSL)
+ addPrimitives(ByteClass, nme.LSR, LSR)
+ addPrimitives(ByteClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(ByteClass, nme.toByte, B2B)
+ addPrimitives(ByteClass, nme.toShort, B2S)
+ addPrimitives(ByteClass, nme.toChar, B2C)
+ addPrimitives(ByteClass, nme.toInt, B2I)
+ addPrimitives(ByteClass, nme.toLong, B2L)
+ // unary methods
+ addPrimitives(ByteClass, nme.UNARY_+, POS)
+ addPrimitives(ByteClass, nme.UNARY_-, NEG)
+ addPrimitives(ByteClass, nme.UNARY_~, NOT)
+
+ addPrimitives(ByteClass, nme.toFloat, B2F)
+ addPrimitives(ByteClass, nme.toDouble, B2D)
+
+ // scala.Short
+ lazy val ShortClass = defn.ShortClass
+ addPrimitives(ShortClass, nme.EQ, EQ)
+ addPrimitives(ShortClass, nme.NE, NE)
+ addPrimitives(ShortClass, nme.ADD, ADD)
+ addPrimitives(ShortClass, nme.SUB, SUB)
+ addPrimitives(ShortClass, nme.MUL, MUL)
+ addPrimitives(ShortClass, nme.DIV, DIV)
+ addPrimitives(ShortClass, nme.MOD, MOD)
+ addPrimitives(ShortClass, nme.LT, LT)
+ addPrimitives(ShortClass, nme.LE, LE)
+ addPrimitives(ShortClass, nme.GT, GT)
+ addPrimitives(ShortClass, nme.GE, GE)
+ addPrimitives(ShortClass, nme.XOR, XOR)
+ addPrimitives(ShortClass, nme.OR, OR)
+ addPrimitives(ShortClass, nme.AND, AND)
+ addPrimitives(ShortClass, nme.LSL, LSL)
+ addPrimitives(ShortClass, nme.LSR, LSR)
+ addPrimitives(ShortClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(ShortClass, nme.toByte, S2B)
+ addPrimitives(ShortClass, nme.toShort, S2S)
+ addPrimitives(ShortClass, nme.toChar, S2C)
+ addPrimitives(ShortClass, nme.toInt, S2I)
+ addPrimitives(ShortClass, nme.toLong, S2L)
+ // unary methods
+ addPrimitives(ShortClass, nme.UNARY_+, POS)
+ addPrimitives(ShortClass, nme.UNARY_-, NEG)
+ addPrimitives(ShortClass, nme.UNARY_~, NOT)
+
+ addPrimitives(ShortClass, nme.toFloat, S2F)
+ addPrimitives(ShortClass, nme.toDouble, S2D)
+
+ // scala.Char
+ lazy val CharClass = defn.CharClass
+ addPrimitives(CharClass, nme.EQ, EQ)
+ addPrimitives(CharClass, nme.NE, NE)
+ addPrimitives(CharClass, nme.ADD, ADD)
+ addPrimitives(CharClass, nme.SUB, SUB)
+ addPrimitives(CharClass, nme.MUL, MUL)
+ addPrimitives(CharClass, nme.DIV, DIV)
+ addPrimitives(CharClass, nme.MOD, MOD)
+ addPrimitives(CharClass, nme.LT, LT)
+ addPrimitives(CharClass, nme.LE, LE)
+ addPrimitives(CharClass, nme.GT, GT)
+ addPrimitives(CharClass, nme.GE, GE)
+ addPrimitives(CharClass, nme.XOR, XOR)
+ addPrimitives(CharClass, nme.OR, OR)
+ addPrimitives(CharClass, nme.AND, AND)
+ addPrimitives(CharClass, nme.LSL, LSL)
+ addPrimitives(CharClass, nme.LSR, LSR)
+ addPrimitives(CharClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(CharClass, nme.toByte, C2B)
+ addPrimitives(CharClass, nme.toShort, C2S)
+ addPrimitives(CharClass, nme.toChar, C2C)
+ addPrimitives(CharClass, nme.toInt, C2I)
+ addPrimitives(CharClass, nme.toLong, C2L)
+ // unary methods
+ addPrimitives(CharClass, nme.UNARY_+, POS)
+ addPrimitives(CharClass, nme.UNARY_-, NEG)
+ addPrimitives(CharClass, nme.UNARY_~, NOT)
+ addPrimitives(CharClass, nme.toFloat, C2F)
+ addPrimitives(CharClass, nme.toDouble, C2D)
+
+ // scala.Int
+ lazy val IntClass = defn.IntClass
+ addPrimitives(IntClass, nme.EQ, EQ)
+ addPrimitives(IntClass, nme.NE, NE)
+ addPrimitives(IntClass, nme.ADD, ADD)
+ addPrimitives(IntClass, nme.SUB, SUB)
+ addPrimitives(IntClass, nme.MUL, MUL)
+ addPrimitives(IntClass, nme.DIV, DIV)
+ addPrimitives(IntClass, nme.MOD, MOD)
+ addPrimitives(IntClass, nme.LT, LT)
+ addPrimitives(IntClass, nme.LE, LE)
+ addPrimitives(IntClass, nme.GT, GT)
+ addPrimitives(IntClass, nme.GE, GE)
+ addPrimitives(IntClass, nme.XOR, XOR)
+ addPrimitives(IntClass, nme.OR, OR)
+ addPrimitives(IntClass, nme.AND, AND)
+ addPrimitives(IntClass, nme.LSL, LSL)
+ addPrimitives(IntClass, nme.LSR, LSR)
+ addPrimitives(IntClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(IntClass, nme.toByte, I2B)
+ addPrimitives(IntClass, nme.toShort, I2S)
+ addPrimitives(IntClass, nme.toChar, I2C)
+ addPrimitives(IntClass, nme.toInt, I2I)
+ addPrimitives(IntClass, nme.toLong, I2L)
+ // unary methods
+ addPrimitives(IntClass, nme.UNARY_+, POS)
+ addPrimitives(IntClass, nme.UNARY_-, NEG)
+ addPrimitives(IntClass, nme.UNARY_~, NOT)
+ addPrimitives(IntClass, nme.toFloat, I2F)
+ addPrimitives(IntClass, nme.toDouble, I2D)
+
+ // scala.Long
+ lazy val LongClass = defn.LongClass
+ addPrimitives(LongClass, nme.EQ, EQ)
+ addPrimitives(LongClass, nme.NE, NE)
+ addPrimitives(LongClass, nme.ADD, ADD)
+ addPrimitives(LongClass, nme.SUB, SUB)
+ addPrimitives(LongClass, nme.MUL, MUL)
+ addPrimitives(LongClass, nme.DIV, DIV)
+ addPrimitives(LongClass, nme.MOD, MOD)
+ addPrimitives(LongClass, nme.LT, LT)
+ addPrimitives(LongClass, nme.LE, LE)
+ addPrimitives(LongClass, nme.GT, GT)
+ addPrimitives(LongClass, nme.GE, GE)
+ addPrimitives(LongClass, nme.XOR, XOR)
+ addPrimitives(LongClass, nme.OR, OR)
+ addPrimitives(LongClass, nme.AND, AND)
+ addPrimitives(LongClass, nme.LSL, LSL)
+ addPrimitives(LongClass, nme.LSR, LSR)
+ addPrimitives(LongClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(LongClass, nme.toByte, L2B)
+ addPrimitives(LongClass, nme.toShort, L2S)
+ addPrimitives(LongClass, nme.toChar, L2C)
+ addPrimitives(LongClass, nme.toInt, L2I)
+ addPrimitives(LongClass, nme.toLong, L2L)
+ // unary methods
+ addPrimitives(LongClass, nme.UNARY_+, POS)
+ addPrimitives(LongClass, nme.UNARY_-, NEG)
+ addPrimitives(LongClass, nme.UNARY_~, NOT)
+ addPrimitives(LongClass, nme.toFloat, L2F)
+ addPrimitives(LongClass, nme.toDouble, L2D)
+
+ // scala.Float
+ lazy val FloatClass = defn.FloatClass
+ addPrimitives(FloatClass, nme.EQ, EQ)
+ addPrimitives(FloatClass, nme.NE, NE)
+ addPrimitives(FloatClass, nme.ADD, ADD)
+ addPrimitives(FloatClass, nme.SUB, SUB)
+ addPrimitives(FloatClass, nme.MUL, MUL)
+ addPrimitives(FloatClass, nme.DIV, DIV)
+ addPrimitives(FloatClass, nme.MOD, MOD)
+ addPrimitives(FloatClass, nme.LT, LT)
+ addPrimitives(FloatClass, nme.LE, LE)
+ addPrimitives(FloatClass, nme.GT, GT)
+ addPrimitives(FloatClass, nme.GE, GE)
+ // conversions
+ addPrimitives(FloatClass, nme.toByte, F2B)
+ addPrimitives(FloatClass, nme.toShort, F2S)
+ addPrimitives(FloatClass, nme.toChar, F2C)
+ addPrimitives(FloatClass, nme.toInt, F2I)
+ addPrimitives(FloatClass, nme.toLong, F2L)
+ addPrimitives(FloatClass, nme.toFloat, F2F)
+ addPrimitives(FloatClass, nme.toDouble, F2D)
+ // unary methods
+ addPrimitives(FloatClass, nme.UNARY_+, POS)
+ addPrimitives(FloatClass, nme.UNARY_-, NEG)
+
+ // scala.Double
+ lazy val DoubleClass = defn.DoubleClass
+ addPrimitives(DoubleClass, nme.EQ, EQ)
+ addPrimitives(DoubleClass, nme.NE, NE)
+ addPrimitives(DoubleClass, nme.ADD, ADD)
+ addPrimitives(DoubleClass, nme.SUB, SUB)
+ addPrimitives(DoubleClass, nme.MUL, MUL)
+ addPrimitives(DoubleClass, nme.DIV, DIV)
+ addPrimitives(DoubleClass, nme.MOD, MOD)
+ addPrimitives(DoubleClass, nme.LT, LT)
+ addPrimitives(DoubleClass, nme.LE, LE)
+ addPrimitives(DoubleClass, nme.GT, GT)
+ addPrimitives(DoubleClass, nme.GE, GE)
+ // conversions
+ addPrimitives(DoubleClass, nme.toByte, D2B)
+ addPrimitives(DoubleClass, nme.toShort, D2S)
+ addPrimitives(DoubleClass, nme.toChar, D2C)
+ addPrimitives(DoubleClass, nme.toInt, D2I)
+ addPrimitives(DoubleClass, nme.toLong, D2L)
+ addPrimitives(DoubleClass, nme.toFloat, D2F)
+ addPrimitives(DoubleClass, nme.toDouble, D2D)
+ // unary methods
+ addPrimitives(DoubleClass, nme.UNARY_+, POS)
+ addPrimitives(DoubleClass, nme.UNARY_-, NEG)
+
+
+ primitives.toMap
+ }
+
+ def isPrimitive(fun: Tree): Boolean = {
+ (primitives contains fun.symbol(ctx)) ||
+ (fun.symbol(ctx) == NoSymbol // the only trees that do not have a symbol assigned are array.{update,select,length,clone}}
+ && (fun match {
+ case Select(_, StdNames.nme.clone_) => false // but array.clone is NOT a primitive op.
+ case _ => true
+ }))
+ }
+
+}
+
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index c414de130..943b54d7f 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -14,6 +14,9 @@ import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
import dotty.tools.dotc.core.Denotations.SingleDenotation
+
+import dotty.tools.backend.jvm.{LabelDefs, GenBCode}
+
class Compiler {
/** Meta-ordering constraint:
@@ -61,7 +64,8 @@ class Compiler {
List(new LambdaLift,
new Flatten,
new RestoreScopes),
- List(new PrivateToStatic)
+ List(/*new PrivateToStatic,*/ new CollectEntryPoints, new LabelDefs),
+ List(new GenBCode)
)
var runId = 1
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 462c223fb..8fdc4a9db 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -361,7 +361,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
val constrSym = modcls.primaryConstructor orElse ctx.newDefaultConstructor(modcls).entered
val constr = DefDef(constrSym.asTerm, EmptyTree)
val clsdef = ClassDef(modcls, constr, body)
- val valdef = ValDef(sym, New(modcls.typeRef))
+ val valdef = ValDef(sym, New(modcls.typeRef).select(constrSym).appliedToNone)
Thicket(valdef, clsdef)
}
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index 9afe96c96..35c3ac16a 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -26,8 +26,8 @@ class ScalaSettings extends Settings.SettingGroup {
val nowarn = BooleanSetting("-nowarn", "Generate no warnings.")
val print = BooleanSetting("-print", "Print program with Scala-specific features removed.")
val target = ChoiceSetting("-target", "target", "Target platform for object files. All JVM 1.5 targets are deprecated.",
- List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "msil"),
- "jvm-1.6")
+ List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "jvm-1.8", "msil"),
+ "jvm-1.8")
val unchecked = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.")
val uniqid = BooleanSetting("-uniqid", "Uniquely tag all identifiers in debugging output.")
val usejavacp = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.")
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 19d175088..a7c7ac3c6 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -269,11 +269,11 @@ class Definitions {
// fundamental classes
lazy val StringClass = ctx.requiredClass("java.lang.String")
- lazy val StringModule = StringClass.moduleClass
+ lazy val StringModule = StringClass.linkedClass
lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final)
lazy val String_valueOf_Object = StringModule.info.member(nme.valueOf).suchThat(_.info.firstParamTypes match {
- case List(pt) => pt isRef ObjectClass
+ case List(pt) => (pt isRef AnyClass) || (pt isRef ObjectClass)
case _ => false
}).symbol
@@ -398,7 +398,7 @@ class Definitions {
def apply(elem: Type)(implicit ctx: Context) =
if (ctx.erasedTypes) JavaArrayType(elem)
else ArrayClass.typeRef.appliedTo(elem :: Nil)
- def unapply(tp: Type)(implicit ctx: Context) = tp.dealias match {
+ def unapply(tp: Type)(implicit ctx: Context): Option[Type] = tp.dealias match {
case at: RefinedType if (at isRef ArrayClass) && at.argInfos.length == 1 => Some(at.argInfos.head)
case _ => None
}
diff --git a/src/dotty/tools/dotc/core/Names.scala b/src/dotty/tools/dotc/core/Names.scala
index cf53d0445..f0d3f02eb 100644
--- a/src/dotty/tools/dotc/core/Names.scala
+++ b/src/dotty/tools/dotc/core/Names.scala
@@ -200,7 +200,7 @@ object Names {
private final val fillFactor = 0.7
/** Memory to store all names sequentially. */
- private var chrs: Array[Char] = new Array[Char](InitialNameSize)
+ private[dotty] var chrs: Array[Char] = new Array[Char](InitialNameSize)
/** The number of characters filled. */
private var nc = 0
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index 5777c0f5b..70dd4296a 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -3,6 +3,7 @@ package core
import Periods._
import Contexts._
+import dotty.tools.backend.jvm.GenBCode
import util.DotClass
import DenotTransformers._
import Denotations._
@@ -171,6 +172,7 @@ object Phases {
private val flattenCache = new PhaseCache(classOf[Flatten])
private val explicitOuterCache = new PhaseCache(classOf[ExplicitOuter])
private val gettersCache = new PhaseCache(classOf[Getters])
+ private val genBCodeCache = new PhaseCache(classOf[GenBCode])
def typerPhase = typerCache.phase
def refchecksPhase = refChecksCache.phase
@@ -179,6 +181,7 @@ object Phases {
def flattenPhase = flattenCache.phase
def explicitOuterPhase = explicitOuterCache.phase
def gettersPhase = gettersCache.phase
+ def genBCodePhase = genBCodeCache.phase
def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id
}
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index 24e948fa9..04bcf616d 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -510,6 +510,9 @@ object StdNames {
val wrap: N = "wrap"
val zero: N = "zero"
val zip: N = "zip"
+ val nothingRuntimeClass: N = "scala.runtime.Nothing$"
+ val nullRuntimeClass: N = "scala.runtime.Null$"
+
val synthSwitch: N = "$synthSwitch"
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index a05296802..eccdcbfb9 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -324,6 +324,9 @@ object SymDenotations {
final def isAnonymousClass(implicit ctx: Context): Boolean =
isClass && (initial.asSymDenotation.name startsWith tpnme.ANON_CLASS)
+ final def isAnonymousFunction(implicit ctx: Context) =
+ this.symbol.is(Method) && (initial.asSymDenotation.name startsWith nme.ANON_FUN)
+
/** Is symbol a primitive value class? */
def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains symbol
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 473b23f7b..a1ca7796f 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -29,6 +29,7 @@ import collection.{mutable, Seq, breakOut}
import config.Config
import config.Printers._
import annotation.tailrec
+import Flags.FlagSet
import language.implicitConversions
object Types {
@@ -523,6 +524,18 @@ object Types {
.toList.map(d => TermRef.withSig(this, d.symbol.asTerm))
}
+ /** The set of member classes of this type */
+ final def memberClasses(implicit ctx: Context): Seq[SingleDenotation] = track("implicitMembers") {
+ memberDenots(typeNameFilter,
+ (name, buf) => buf ++= member(name).altsWith(x => x.isClass))
+ }
+
+ /** The set of members of this type having at least one of `requiredFlags` but none of `excludedFlags` set */
+ final def membersBasedOnFlags(requiredFlags: FlagSet, excludedFlags: FlagSet)(implicit ctx: Context): Seq[SingleDenotation] = track("implicitMembers") {
+ memberDenots(takeAllFilter,
+ (name, buf) => buf ++= member(name).altsWith(x => x.is(requiredFlags, butNot = excludedFlags)))
+ }
+
/** The info of `sym`, seen as a member of this type. */
final def memberInfo(sym: Symbol)(implicit ctx: Context): Type =
sym.info.asSeenFrom(this, sym.owner)
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index 8231c25af..cc3d3eb7f 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -876,7 +876,9 @@ class ClassfileParser(
val start = starts(index)
if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start)
val name = getExternalName(in.getChar(start + 1))
- if (name.isModuleClassName) c = ctx.requiredModule(name.sourceModuleName)
+ if (name.isModuleClassName && (name ne nme.nothingRuntimeClass) && (name ne nme.nullRuntimeClass))
+ // Null$ and Nothing$ ARE classes
+ c = ctx.requiredModule(name.sourceModuleName)
else c = classNameToSymbol(name)
values(index) = c
}
diff --git a/src/dotty/tools/dotc/transform/LambdaLift.scala b/src/dotty/tools/dotc/transform/LambdaLift.scala
index 95c5cd529..c8dacd1d7 100644
--- a/src/dotty/tools/dotc/transform/LambdaLift.scala
+++ b/src/dotty/tools/dotc/transform/LambdaLift.scala
@@ -257,8 +257,8 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
case mt @ MethodType(pnames, ptypes) =>
val ps = proxies(local.skipConstructor)
MethodType(
- pnames ++ ps.map(_.name.asTermName),
- ptypes ++ ps.map(_.info),
+ ps.map(_.name.asTermName) ++ pnames,
+ ps.map(_.info) ++ ptypes,
mt.resultType)
case info => info
}
@@ -340,7 +340,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
private def addFreeArgs(sym: Symbol, args: List[Tree])(implicit ctx: Context, info: TransformerInfo) =
free get sym match {
- case Some(fvs) => args ++ fvs.toList.map(proxyRef(_))
+ case Some(fvs) => fvs.toList.map(proxyRef(_)) ++ args
case _ => args
}
@@ -354,9 +354,9 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
transformFollowingDeep(ValDef(proxy.asTerm).withPos(tree.pos)).asInstanceOf[ValDef])
tree match {
case tree: DefDef =>
- cpy.DefDef(tree)(vparamss = tree.vparamss.map(_ ++ freeParamDefs))
+ cpy.DefDef(tree)(vparamss = tree.vparamss.map(freeParamDefs ++ _))
case tree: Template =>
- cpy.Template(tree)(body = tree.body ++ freeParamDefs)
+ cpy.Template(tree)(body = freeParamDefs ++ tree.body)
}
}
diff --git a/src/dotty/tools/dotc/transform/MixinOps.scala b/src/dotty/tools/dotc/transform/MixinOps.scala
index de15b045f..e6074323a 100644
--- a/src/dotty/tools/dotc/transform/MixinOps.scala
+++ b/src/dotty/tools/dotc/transform/MixinOps.scala
@@ -4,15 +4,14 @@ package transform
import core._
import Symbols._, Types._, Contexts._, SymDenotations._, DenotTransformers._, Flags._
import util.Positions._
+import SymUtils._
import StdNames._, NameOps._
class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: Context) {
import ast.tpd._
- val superCls: Symbol = cls.classInfo.parents.head.symbol
- val mixins: List[ClassSymbol] =
- if (cls is Trait) Nil
- else cls.baseClasses.tail.takeWhile(_ ne superCls).reverse
+ val superCls: Symbol = cls.superClass
+ val mixins: List[ClassSymbol] = cls.mixins
def implementation(member: TermSymbol): TermSymbol =
member.copy(
diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala
index 7d485f64c..9274150b1 100644
--- a/src/dotty/tools/dotc/transform/SymUtils.scala
+++ b/src/dotty/tools/dotc/transform/SymUtils.scala
@@ -24,6 +24,32 @@ object SymUtils {
class SymUtils(val self: Symbol) extends AnyVal {
import SymUtils._
+ def superClass(implicit ctx: Context) = {
+ val parents = self.asClass.classInfo.parents
+ if (parents.isEmpty) NoSymbol
+ else parents.head.symbol
+ }
+
+
+ /**
+ * For a class: All interfaces implemented by a class except for those inherited through the superclass.
+ * For a trait: all parent traits
+ */
+
+ def superInterfaces(implicit ctx: Context) = {
+ val superCls = self.superClass
+ val baseClasses = self.asClass.baseClasses
+ if (baseClasses.isEmpty) Nil
+ else baseClasses.tail.takeWhile(_ ne superCls).reverse
+
+ }
+
+ /** All interfaces implemented by a class, except for those inherited through the superclass. */
+ def mixins(implicit ctx: Context) = {
+ if (self is Trait) Nil
+ else superInterfaces
+ }
+
def isTypeTestOrCast(implicit ctx: Context): Boolean =
self == defn.Any_asInstanceOf || self == defn.Any_isInstanceOf
@@ -36,9 +62,6 @@ class SymUtils(val self: Symbol) extends AnyVal {
final def skipConstructor(implicit ctx: Context): Symbol =
if (self.isConstructor) self.owner else self
- final def isAnonymousFunction(implicit ctx: Context): Boolean =
- self.is(Method) && (self.denot.initial.asSymDenotation.name startsWith nme.ANON_FUN)
-
/** The logically enclosing method or class for this symbol.
* Instead of constructors one always picks the enclosing class.
*/