aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDmitry Petrashko <dmitry.petrashko@gmail.com>2014-11-27 15:34:39 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-12-16 13:14:59 +0100
commit0db32d2d221aed7b727ff79d241894c4f7d5a2a6 (patch)
tree25a9b56c0ca395da72e42372380d4614ef0dd860 /src
parentc742e95b808ab123a43fd10968100fab37321fe2 (diff)
downloaddotty-0db32d2d221aed7b727ff79d241894c4f7d5a2a6.tar.gz
dotty-0db32d2d221aed7b727ff79d241894c4f7d5a2a6.tar.bz2
dotty-0db32d2d221aed7b727ff79d241894c4f7d5a2a6.zip
New phase: collectEntryPoints
collects entry points and registers them in backend
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/backend/jvm/CollectEntryPoints.scala120
-rw-r--r--src/dotty/tools/backend/jvm/DottyBackendInterface.scala70
2 files changed, 121 insertions, 69 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
index f1e685a0d..71c35274e 100644
--- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
+++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -395,75 +395,7 @@ abstract class DottyBackendInterface()(implicit ctx: Context) extends BackendInt
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 = {
- 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) != 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.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)
- }
- }
- }
- }
- }
- }
+ def isJavaEntryPoint: Boolean = CollectEntryPoints.isJavaEntyPoint(sym)
def isClassConstructor: Boolean = sym.name == nme.CONSTRUCTOR