Skip to content

Commit

Permalink
Keep old version of MainProxies for scala#14156
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheeandres committed Jan 22, 2022
1 parent 5519509 commit 92db848
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 1 deletion.
91 changes: 90 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/MainProxies.scala
Expand Up @@ -47,6 +47,96 @@ import Annotations.Annotation
* }
*/
object MainProxies {
def mainProxiesOld(stats: List[tpd.Tree])(using Context): List[untpd.Tree] = {
import tpd._
def mainMethods(stats: List[Tree]): List[Symbol] = stats.flatMap {
case stat: DefDef if stat.symbol.hasAnnotation(defn.MainAnnot) =>
stat.symbol :: Nil
case stat @ TypeDef(name, impl: Template) if stat.symbol.is(Module) =>
mainMethods(impl.body)
case _ =>
Nil
}
mainMethods(stats).flatMap(mainProxyOld)
}

import untpd._
def mainProxyOld(mainFun: Symbol)(using Context): List[TypeDef] = {
val mainAnnotSpan = mainFun.getAnnotation(defn.MainAnnot).get.tree.span
def pos = mainFun.sourcePos
val argsRef = Ident(nme.args)

def addArgs(call: untpd.Tree, mt: MethodType, idx: Int): untpd.Tree =
if (mt.isImplicitMethod) {
report.error(s"@main method cannot have implicit parameters", pos)
call
}
else {
val args = mt.paramInfos.zipWithIndex map {
(formal, n) =>
val (parserSym, formalElem) =
if (formal.isRepeatedParam) (defn.CLP_parseRemainingArguments, formal.argTypes.head)
else (defn.CLP_parseArgument, formal)
val arg = Apply(
TypeApply(ref(parserSym.termRef), TypeTree(formalElem) :: Nil),
argsRef :: Literal(Constant(idx + n)) :: Nil)
if (formal.isRepeatedParam) repeated(arg) else arg
}
val call1 = Apply(call, args)
mt.resType match {
case restpe: MethodType =>
if (mt.paramInfos.lastOption.getOrElse(NoType).isRepeatedParam)
report.error(s"varargs parameter of @main method must come last", pos)
addArgs(call1, restpe, idx + args.length)
case _ =>
call1
}
}

var result: List[TypeDef] = Nil
if (!mainFun.owner.isStaticOwner)
report.error(s"@main method is not statically accessible", pos)
else {
var call = ref(mainFun.termRef)
mainFun.info match {
case _: ExprType =>
case mt: MethodType =>
call = addArgs(call, mt, 0)
case _: PolyType =>
report.error(s"@main method cannot have type parameters", pos)
case _ =>
report.error(s"@main can only annotate a method", pos)
}
val errVar = Ident(nme.error)
val handler = CaseDef(
Typed(errVar, TypeTree(defn.CLP_ParseError.typeRef)),
EmptyTree,
Apply(ref(defn.CLP_showError.termRef), errVar :: Nil))
val body = Try(call, handler :: Nil, EmptyTree)
val mainArg = ValDef(nme.args, TypeTree(defn.ArrayType.appliedTo(defn.StringType)), EmptyTree)
.withFlags(Param)
/** Replace typed `Ident`s that have been typed with a TypeSplice with the reference to the symbol.
* The annotations will be retype-checked in another scope that may not have the same imports.
*/
def insertTypeSplices = new TreeMap {
override def transform(tree: Tree)(using Context): Tree = tree match
case tree: tpd.Ident @unchecked => TypedSplice(tree)
case tree => super.transform(tree)
}
val annots = mainFun.annotations
.filterNot(_.matches(defn.MainAnnot))
.map(annot => insertTypeSplices.transform(annot.tree))
val mainMeth = DefDef(nme.main, (mainArg :: Nil) :: Nil, TypeTree(defn.UnitType), body)
.withFlags(JavaStatic)
.withAnnotations(annots)
val mainTempl = Template(emptyConstructor, Nil, Nil, EmptyValDef, mainMeth :: Nil)
val mainCls = TypeDef(mainFun.name.toTypeName, mainTempl)
.withFlags(Final | Invisible)
if (!ctx.reporter.hasErrors) result = mainCls.withSpan(mainAnnotSpan.toSynthetic) :: Nil
}
result
}

private type DefaultValueSymbols = Map[Int, Symbol]
private type ParameterAnnotationss = Seq[Seq[Annotation]]

Expand Down Expand Up @@ -95,7 +185,6 @@ object MainProxies {
mainMethods(EmptyTree, stats).flatMap(mainProxy)
}

import untpd._
def mainProxy(mainFun: Symbol, paramAnnotations: ParameterAnnotationss, defaultValueSymbols: DefaultValueSymbols, docComment: Option[Comment])(using Context): List[TypeDef] = {
val mainAnnot = mainFun.getAnnotation(defn.MainAnnot).get
def pos = mainFun.sourcePos
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Expand Up @@ -871,6 +871,12 @@ class Definitions {
@tu lazy val MainAnnotCommand_varargGetter: Symbol = MainAnnotCommand.requiredMethod("varargGetter")
@tu lazy val MainAnnotCommand_run: Symbol = MainAnnotCommand.requiredMethod("run")

@tu lazy val CommandLineParserModule: Symbol = requiredModule("scala.util.CommandLineParser")
@tu lazy val CLP_ParseError: ClassSymbol = CommandLineParserModule.requiredClass("ParseError").typeRef.symbol.asClass
@tu lazy val CLP_parseArgument: Symbol = CommandLineParserModule.requiredMethod("parseArgument")
@tu lazy val CLP_parseRemainingArguments: Symbol = CommandLineParserModule.requiredMethod("parseRemainingArguments")
@tu lazy val CLP_showError: Symbol = CommandLineParserModule.requiredMethod("showError")

@tu lazy val TupleTypeRef: TypeRef = requiredClassRef("scala.Tuple")
def TupleClass(using Context): ClassSymbol = TupleTypeRef.symbol.asClass
@tu lazy val Tuple_cons: Symbol = TupleClass.requiredMethod("*:")
Expand Down

0 comments on commit 92db848

Please sign in to comment.