Skip to content

Commit 2d9c719

Browse files
Add partial cross-compilation for Scala 3 (#4549)
1 parent ae18f18 commit 2d9c719

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2451
-101
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ jobs:
9090
$CHISEL_FIRTOOL_PATH/firtool -version >> $GITHUB_STEP_SUMMARY
9191
echo \`\`\` >> $GITHUB_STEP_SUMMARY
9292
- name: Test
93-
run: ./mill -j0 firrtl[_].test + svsim[_].test + chisel[_].test
93+
run: ./mill -j0 firrtl[].test + svsim[].test + chisel[].test
9494
- name: Binary compatibility
9595
# TODO either make this also check the plugin or decide that we don't
9696
# support binary compatibility for the plugin
@@ -132,7 +132,7 @@ jobs:
132132
$CHISEL_FIRTOOL_PATH/firtool -version >> $GITHUB_STEP_SUMMARY
133133
echo \`\`\` >> $GITHUB_STEP_SUMMARY
134134
- name: Compile with Mill
135-
run: ./mill __.compile
135+
run: ./mill compileAll
136136

137137
doc:
138138
name: Formatting
@@ -183,7 +183,7 @@ jobs:
183183
dir=$(dirname $(which firtool))
184184
echo "CHISEL_FIRTOOL_PATH=$dir" >> "$GITHUB_ENV"
185185
- name: Integration Tests
186-
run: ./mill -j0 integrationTests[_].test
186+
run: ./mill -j0 integrationTests[].test
187187

188188
# Currently just a sanity check that the benchmarking flow works
189189
benchmark:

build.sc

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,34 @@ object v extends Module {
3434
val java21Min213 = 11
3535
val minVersion = if (javaVersion > 11) java21Min213 else 0
3636
val versions = minVersion to latest213
37-
versions.map(v => s"2.13.$v").toSeq
37+
val versionSeq = versions.map(v => s"2.13.$v").toSeq
38+
versionSeq ++ Seq("3.3.4")
3839
}
3940

4041
val scalaCrossVersions = Seq(
41-
"2.13.15"
42+
"2.13.15",
43+
"3.3.4"
4244
)
4345

4446
def isScala3(ver: String): Boolean = ver.startsWith("3.")
4547

48+
def buildUnits(): Seq[ScalaModule] = {
49+
scalaCrossVersions.flatMap { ver =>
50+
Seq(chisel(ver), stdlib(ver), unipublish)
51+
} ++ scalaCrossVersions.filterNot(isScala3(_)).flatMap { ver2 =>
52+
Seq(
53+
chisel(ver2).test,
54+
firrtl(ver2).test,
55+
svsim(ver2).test,
56+
integrationTests(ver2).test,
57+
litutility(ver2),
58+
panamaconverter(ver2),
59+
panamalib(ver2),
60+
panamaom(ver2)
61+
)
62+
}
63+
}
64+
4665
val scalaVersion = scalaCrossVersions.head
4766
val jmhVersion = "1.37"
4867
val osLib = ivy"com.lihaoyi::os-lib:0.10.0"
@@ -96,6 +115,10 @@ object v extends Module {
96115
)
97116
}
98117

118+
def compileAll() = T.command {
119+
T.traverse(v.buildUnits())(_.compile)()
120+
}
121+
99122
trait ChiselPublishModule extends CiReleaseModule {
100123
// Publish information
101124
def pomSettings = PomSettings(
@@ -251,7 +274,7 @@ trait Core extends CrossSbtModule with HasScala2MacroAnno with ScalafmtModule {
251274
)
252275

253276
override def ivyDeps = if (v.isScala3(crossScalaVersion)) {
254-
super.ivyDeps() ++ commonDeps
277+
super.ivyDeps() ++ commonDeps ++ Agg(v.firtoolResolver.withDottyCompat(scalaVersion()))
255278
} else {
256279
super.ivyDeps() ++ commonDeps ++ Agg(v.firtoolResolver)
257280
}
@@ -309,7 +332,13 @@ trait Plugin extends CrossSbtModule with ScalafmtModule with ChiselPublishModule
309332
def scalaReflectIvy = v.scalaReflect(crossScalaVersion)
310333
def scalaCompilerIvy: Dep = v.scalaCompiler(crossScalaVersion)
311334

312-
def ivyDeps = super.ivyDeps() ++ Agg(scalaLibraryIvy, scalaReflectIvy, scalaCompilerIvy)
335+
def ivyDeps = T {
336+
if (!v.isScala3(crossScalaVersion)) {
337+
super.ivyDeps() ++ Agg(scalaLibraryIvy, scalaReflectIvy, scalaCompilerIvy)
338+
} else {
339+
super.ivyDeps()
340+
}
341+
}
313342
}
314343

315344
object chisel extends Cross[Chisel](v.scalaCrossVersions)

core/src/main/scala-2/chisel3/experimental/dataview/ChiselSubtypeOf.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import scala.reflect.macros.blackbox.Context
2727
*/
2828
sealed trait ChiselSubtypeOf[A, B]
2929

30+
// return an empty tree here instead of a quasiquote for scala3 compatibility
3031
object ChiselSubtypeOf {
3132
// TODO return an empty tree here instead of a quasiquote for scala3 compatibility
3233
def genChiselSubtypeOf[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context): c.Tree = {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package chisel3.experimental.hierarchy.core
2+
3+
import chisel3._
4+
import scala.reflect.runtime.universe.TypeTag
5+
6+
trait HierarchyProto[+A] {
7+
private[chisel3] def underlying: Underlying[A]
8+
private[chisel3] def proto: A = underlying match {
9+
case Proto(value) => value
10+
case Clone(i: IsClone[A]) => i.getProto
11+
}
12+
}
13+
14+
trait HierarchyIsA[+A] extends HierarchyProto[A] {
15+
// This code handles a special-case where, within an mdoc context, the type returned from
16+
// scala reflection (typetag) looks different than when returned from java reflection.
17+
// This function detects this case and reshapes the string to match.
18+
private def modifyReplString(clz: String): String = {
19+
if (clz != null) {
20+
clz.split('.').toList match {
21+
case "repl" :: "MdocSession" :: app :: rest => s"$app.this." + rest.mkString(".")
22+
case other => clz
23+
}
24+
} else clz
25+
}
26+
27+
private lazy val superClasses = calculateSuperClasses(super.proto.getClass())
28+
private def calculateSuperClasses(clz: Class[_]): Set[String] = {
29+
if (clz != null) {
30+
Set(modifyReplString(clz.getCanonicalName())) ++
31+
clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++
32+
calculateSuperClasses(clz.getSuperclass())
33+
} else {
34+
Set.empty[String]
35+
}
36+
}
37+
private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz)
38+
39+
/** Determine whether underlying proto is of type provided.
40+
*
41+
* @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class.
42+
* @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure.
43+
* @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type
44+
*
45+
* E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String]
46+
* @return Whether underlying proto is of provided type (with caveats outlined above)
47+
*/
48+
def isA[B: TypeTag]: Boolean = {
49+
val tptag = implicitly[TypeTag[B]]
50+
// drop any type information for the comparison, because the proto will not have that information.
51+
val name = tptag.tpe.toString.takeWhile(_ != '[')
52+
inBaseClasses(name)
53+
}
54+
}

0 commit comments

Comments
 (0)