diff options
author | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-11-27 15:34:39 +0100 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-12-16 13:14:59 +0100 |
commit | 0db32d2d221aed7b727ff79d241894c4f7d5a2a6 (patch) | |
tree | 25a9b56c0ca395da72e42372380d4614ef0dd860 /src | |
parent | c742e95b808ab123a43fd10968100fab37321fe2 (diff) | |
download | dotty-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.scala | 120 | ||||
-rw-r--r-- | src/dotty/tools/backend/jvm/DottyBackendInterface.scala | 70 |
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 |