Skip to content

Commit 63477ba

Browse files
committed
Support missing syntax variants for compiler options
1 parent d760454 commit 63477ba

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

modules/cli/src/main/scala/scala/cli/commands/shared/ScalacOptions.scala

+15-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,19 @@ object ScalacOptions {
4141
private val scalacOptionsPurePrefixes =
4242
Set("-V", "-W", "-X", "-Y")
4343
private val scalacOptionsPrefixes =
44-
Set("-g", "-language", "-opt", "-P", "-target", "-source") ++ scalacOptionsPurePrefixes
44+
Set("-P") ++ scalacOptionsPurePrefixes
4545
private val scalacAliasedOptions = // these options don't require being passed after -O and accept an arg
46-
Set("-encoding", "-release", "-color", YScriptRunnerOption)
46+
Set(
47+
"-encoding",
48+
"-release",
49+
"-color",
50+
"-g",
51+
"-language",
52+
"-opt",
53+
"-target",
54+
"-source",
55+
YScriptRunnerOption
56+
)
4757
private val scalacNoArgAliasedOptions = // these options don't require being passed after -O and don't accept an arg
4858
Set(
4959
"-unchecked",
@@ -104,6 +114,9 @@ object ScalacOptions {
104114
Right(Some((Some(acc.getOrElse(Nil) :+ h), t)))
105115
case h :: t if scalacNoArgAliasedOptions.contains(h) =>
106116
Right(Some((Some(acc.getOrElse(Nil) :+ h), t)))
117+
case h :: t
118+
if scalacAliasedOptions.exists(o => h.startsWith(o + ":")) &&
119+
h.count(_ == ':') == 1 => Right(Some((Some(acc.getOrElse(Nil) :+ h), t)))
107120
case h :: t if scalacAliasedOptions.contains(h) =>
108121
// check if the next scalac arg is a different option or a param to the current option
109122
val maybeOptionArg = t.headOption.filter(!_.startsWith("-"))

modules/integration/src/test/scala/scala/cli/integration/CompileScalacCompatTestDefinitions.scala

+72
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,78 @@ trait CompileScalacCompatTestDefinitions { _: CompileTestDefinitions =>
3131
}
3232
}
3333

34+
// Given the vast number of ways compiler options can be passed from the CLI,
35+
// we test them all (or most, at the very least), as a (perhaps overkill) sanity check.
36+
// Pieces of the existing `-language:*` test are reused, but kept separate for clarity.
37+
{
38+
val modes @ Seq(viaDirective, viaCli, viaCliWithExplicitOpt, mixed, mixedWithExplicitOpt) =
39+
Seq("directive", "cli", "cli with -O", "mixed", "mixed with -O")
40+
for {
41+
mode <- modes
42+
if actualScalaVersion == Constants.scala3Next
43+
syntaxVariant <- Seq(
44+
Seq(Seq("-color:never"), Seq("-language:noAutoTupling"), Seq("-language:strictEquality")),
45+
Seq(
46+
Seq("-color", "never"),
47+
Seq("-language", "noAutoTupling"),
48+
Seq("-language", "strictEquality")
49+
),
50+
Seq(Seq("-color:never"), Seq("\"-language:noAutoTupling,strictEquality\"")),
51+
Seq(Seq("-color", "never"), Seq("-language", "\"noAutoTupling,strictEquality\""))
52+
)
53+
(cliOpts, directiveOpts) = {
54+
val (initialCliOpts, initialDirectiveOpts) = mode match {
55+
case m if m == mixed => syntaxVariant.splitAt(syntaxVariant.length - 1)
56+
case m if m == mixedWithExplicitOpt =>
57+
val (initialCliOpts, initialDirectiveOpts) =
58+
syntaxVariant.splitAt(syntaxVariant.length - 1)
59+
initialCliOpts.map(_.flatMap(o => Seq("-O", o))) -> initialDirectiveOpts
60+
case c if c == viaCli => syntaxVariant -> Nil
61+
case c if c == viaCliWithExplicitOpt =>
62+
syntaxVariant.map(_.flatMap(o => Seq("-O", o))) -> Nil
63+
case _ => Nil -> syntaxVariant
64+
}
65+
initialCliOpts.flatten.map(_.filter(_ != '"')) -> initialDirectiveOpts.flatten
66+
}
67+
cliOptsString = cliOpts.mkString(" ")
68+
directiveOptsString = directiveOpts.mkString(" ")
69+
includeDirective =
70+
(mode == viaDirective || mode == mixed || mode == mixedWithExplicitOpt) && directiveOpts.nonEmpty
71+
directiveString = if (includeDirective) s"//> using options $directiveOptsString" else ""
72+
allOptsString = mode match {
73+
case m if m.startsWith(mixed) =>
74+
s"opts passed via command line: $cliOptsString, opts passed via directive: $directiveString"
75+
case c if c.startsWith(viaCli) =>
76+
s"opts passed via command line: $cliOptsString"
77+
case _ =>
78+
s"opts passed via directive: $directiveString"
79+
}
80+
} test(s"compiler options passed in $mode mode: $allOptsString") {
81+
val sourceFileName = "example.scala"
82+
TestInputs(os.rel / sourceFileName ->
83+
s"""//> using scala $actualScalaVersion
84+
|$directiveString
85+
|case class Cat(name: String)
86+
|case class Dog(name: String)
87+
|def strictEquality(c: Cat, d: Dog):Boolean = c == d
88+
|def takesTuple(tpl: Tuple) = ???
89+
|def withTuple() = takesTuple(1, 2)
90+
|""".stripMargin).fromRoot { root =>
91+
val res = os.proc(TestUtil.cli, "compile", sourceFileName, cliOpts)
92+
.call(cwd = root, check = false, stderr = os.Pipe)
93+
println(res.err.trim())
94+
expect(res.exitCode == 1)
95+
val errOutput = res.err.trim()
96+
val expectedStrictEqualityError =
97+
"Values of types Cat and Dog cannot be compared with == or !="
98+
expect(errOutput.contains(expectedStrictEqualityError))
99+
val expectedNoAutoTuplingError =
100+
"too many arguments for method takesTuple: (tpl: Tuple): Nothing"
101+
expect(errOutput.trim().contains(expectedNoAutoTuplingError))
102+
}
103+
}
104+
}
105+
34106
for {
35107
useDirective <- Seq(true, false)
36108
if !Properties.isWin

0 commit comments

Comments
 (0)