Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new main annotation #14841

Merged
merged 2 commits into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
388 changes: 388 additions & 0 deletions library/src/scala/annotation/newMain.scala

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions tests/neg/main-annotation-by-name-param.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
object myProgram:

/** Adds two numbers */
@main def add(num: Int, inc: => Int): Unit = // error
println(s"$num + $inc = ${num + inc}")

end myProgram

object Test:
def callMain(args: Array[String]): Unit =
val clazz = Class.forName("add")
val method = clazz.getMethod("main", classOf[Array[String]])
method.invoke(null, args)

def main(args: Array[String]): Unit =
callMain(Array("2", "3"))
end Test
8 changes: 8 additions & 0 deletions tests/neg/main-annotation-currying.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import scala.annotation.newMain

object myProgram:

@newMain def add(num: Int)(inc: Int): Unit = // error
println(s"$num + $inc = ${num + inc}")

end myProgram
8 changes: 8 additions & 0 deletions tests/neg/main-annotation-generic.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import scala.annotation.newMain

object myProgram:

@newMain def nop[T](t: T): T = // error
t

end myProgram
13 changes: 13 additions & 0 deletions tests/neg/main-annotation-implicit-given.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import scala.annotation.newMain

object myProgram:
implicit val x: Int = 2
given Int = 3

@newMain def showImplicit(implicit num: Int): Unit = // error
println(num)

@newMain def showUsing(using num: Int): Unit = // error
println(num)

end myProgram
8 changes: 8 additions & 0 deletions tests/neg/main-annotation-multiple-annot.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import scala.annotation.newMain

object myProgram:

@newMain @newMain def add1(num: Int, inc: Int): Unit = // error
println(s"$num + $inc = ${num + inc}")

end myProgram
11 changes: 11 additions & 0 deletions tests/neg/main-annotation-nonmethod.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import scala.annotation.newMain

object myProgram:

@newMain val n = 2 // error

@newMain class A // error

@newMain val f = ((s: String) => println(s)) // error

end myProgram
4 changes: 4 additions & 0 deletions tests/neg/main-annotation-nonstatic.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import scala.annotation.newMain

class A:
@newMain def foo(bar: Int) = () // error
12 changes: 12 additions & 0 deletions tests/neg/main-annotation-unknown-parser-1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import scala.annotation.newMain

class MyNumber(val value: Int) {
def +(other: MyNumber): MyNumber = MyNumber(value + other.value)
}

object myProgram:

@newMain def add(num: MyNumber, inc: MyNumber): Unit = // error
println(s"$num + $inc = ${num + inc}")

end myProgram
27 changes: 27 additions & 0 deletions tests/neg/main-annotation-unknown-parser-2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import scala.annotation.newMain
import scala.util.CommandLineParser.FromString

object myProgram:

@newMain def add(num: Test.MyNumber, inc: Test.MyNumber): Unit = // error
val numV = Test.value(num)
val incV = Test.value(inc)
println(s"$numV + $incV = ${numV + incV}")

end myProgram


object Test:
opaque type MyNumber = Int

def create(n: Int): MyNumber = n
def value(n: MyNumber): Int = n

def callMain(args: Array[String]): Unit =
val clazz = Class.forName("add")
val method = clazz.getMethod("main", classOf[Array[String]])
method.invoke(null, args)

def main(args: Array[String]): Unit =
callMain(Array("2", "3"))
end Test
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ val experimentalDefinitionInLibrary = Set(
"scala.annotation.MainAnnotation",
"scala.annotation.MainAnnotation$",

//// New feature: prototype of new version of @main
// This will never be stabilized. When it is ready it should replace the old @main annotation (requires scala.annotation.MainAnnotation).
// Needs user feedback.
"scala.annotation.newMain",
"scala.annotation.newMain$",
"scala.annotation.newMain$.alias",

//// New APIs: Mirror
// Can be stabilized in 3.3.0 or later.
"scala.deriving.Mirror$.fromProductTyped", // This API is a bit convoluted. We may need some more feedback before we can stabilize it.
Expand Down
1 change: 1 addition & 0 deletions tests/run/main-annotation-birthday.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Happy 23rd birthday, Lisa and Peter
32 changes: 32 additions & 0 deletions tests/run/main-annotation-birthday.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import scala.annotation.newMain

/**
* Wishes a happy birthday to lucky people!
*
* @param age the age of the people whose birthday it is
* @param name the name of the luckiest person!
* @param others all the other lucky people
*/
@newMain def happyBirthday(age: Int, name: String, others: String*) =
val suffix =
age % 100 match
case 11 | 12 | 13 => "th"
case _ =>
age % 10 match
case 1 => "st"
case 2 => "nd"
case 3 => "rd"
case _ => "th"
val bldr = new StringBuilder(s"Happy $age$suffix birthday, $name")
for other <- others do bldr.append(" and ").append(other)
println(bldr)

object Test:
def callMain(args: Array[String]): Unit =
val clazz = Class.forName("happyBirthday")
val method = clazz.getMethod("main", classOf[Array[String]])
method.invoke(null, args)

def main(args: Array[String]): Unit =
callMain(Array("23", "Lisa", "Peter"))
end Test
17 changes: 17 additions & 0 deletions tests/run/main-annotation-dash-dash.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
str = x
rest = y,z

str = x
rest = y,z

str = -a
rest = x,y,z

str = x
rest = y,z

str = y
rest = z

Error: missing argument for --str
Usage: foo [--str] <String> [<String> [<String> [...]]]
25 changes: 25 additions & 0 deletions tests/run/main-annotation-dash-dash.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import scala.annotation.newMain

object myProgram:

@newMain def foo(str: String, rest: String*): Unit =
println(s"str = $str")
println(s"rest = ${rest.mkString(",")}")
println()

end myProgram

object Test:
def callMain(args: Array[String]): Unit =
val clazz = Class.forName("foo")
val method = clazz.getMethod("main", classOf[Array[String]])
method.invoke(null, args)

def main(args: Array[String]): Unit =
callMain(Array("x", "y", "z"))
callMain(Array("--", "x", "y", "z"))
callMain(Array("--", "-a", "x", "y", "z"))
callMain(Array("x", "--", "y", "z"))
callMain(Array("--str", "y", "--", "z"))
callMain(Array("--str", "--", "y", "z")) // missing argument for `--str`
end Test
3 changes: 3 additions & 0 deletions tests/run/main-annotation-default-value-1.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
2 + 3 = 5
2 + 1 = 3
0 + 1 = 1
22 changes: 22 additions & 0 deletions tests/run/main-annotation-default-value-1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import scala.annotation.newMain

// Sample main method
object myProgram:

/** Adds two numbers */
@newMain def add(num: Int = 0, inc: Int = 1): Unit =
println(s"$num + $inc = ${num + inc}")

end myProgram

object Test:
def callMain(args: Array[String]): Unit =
val clazz = Class.forName("add")
val method = clazz.getMethod("main", classOf[Array[String]])
method.invoke(null, args)

def main(args: Array[String]): Unit =
callMain(Array("2", "3"))
callMain(Array("2"))
callMain(Array())
end Test
2 changes: 2 additions & 0 deletions tests/run/main-annotation-default-value-2.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
42
OK
33 changes: 33 additions & 0 deletions tests/run/main-annotation-default-value-2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import scala.annotation.newMain

// Sample main method
object myProgram:

@newMain def alwaysPassParam(forbiddenParam: Int = throw new IllegalStateException("This should not be evaluated!")): Unit =
println(forbiddenParam)

end myProgram

object Test:
def hasCauseIllegalStateException(e: Throwable): Boolean =
e.getCause match {
case null => false
case _: IllegalStateException => true
case e: Throwable => hasCauseIllegalStateException(e)
}

def callMain(args: Array[String]): Unit =
val clazz = Class.forName("alwaysPassParam")
val method = clazz.getMethod("main", classOf[Array[String]])
method.invoke(null, args)

def main(args: Array[String]): Unit =
callMain(Array("42"))
try {
callMain(Array())
println("This should not be printed")
}
catch {
case e: Exception if hasCauseIllegalStateException(e) => println("OK")
}
end Test
16 changes: 16 additions & 0 deletions tests/run/main-annotation-flags.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
shortFlags: a = false, b = false
shortFlags: a = true, b = false
shortFlags: a = true, b = true
Error: unused argument: true
Error: unused argument: false
Usage: shortFlags [-a] [-b]
Error: unused argument: true
Usage: shortFlags [-a] [-b]
Error: unused argument: true
Usage: shortFlags [-a] [-b]
longFlags: flag1 = false, flag2 = false
longFlags: flag1 = true, flag2 = false
longFlags: flag1 = true, flag2 = true
mixedFlags: a = false, flag = false
mixedFlags: a = true, flag = false
mixedFlags: a = true, flag = true
41 changes: 41 additions & 0 deletions tests/run/main-annotation-flags.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import scala.annotation.newMain

// Sample main method
object myProgram:

@newMain def shortFlags(a: Boolean, b: Boolean): Unit =
println(s"shortFlags: a = $a, b = $b")

@newMain def longFlags(flag1: Boolean, flag2: Boolean): Unit =
println(s"longFlags: flag1 = $flag1, flag2 = $flag2")

@newMain def mixedFlags(a: Boolean, flag: Boolean): Unit =
println(s"mixedFlags: a = $a, flag = $flag")

end myProgram

object Test:
def callMain(name: String, args: String*): Unit =
val clazz = Class.forName(name)
val method = clazz.getMethod("main", classOf[Array[String]])
method.invoke(null, args.toArray)

def main(args: Array[String]): Unit =
callMain("shortFlags")
callMain("shortFlags", "-a")
callMain("shortFlags", "-a", "-b")
callMain("shortFlags", "true", "false")
callMain("shortFlags", "-a", "true")
callMain("shortFlags", "-b", "true")


callMain("longFlags")
callMain("longFlags", "--flag1")
callMain("longFlags", "--flag1", "--flag2")

callMain("mixedFlags")
callMain("mixedFlags", "-a")
callMain("mixedFlags", "-a", "--flag")


end Test
Loading