Skip to content

Commit 8771b8b

Browse files
committed
add scala 3 support
1 parent 5c8de8b commit 8771b8b

File tree

15 files changed

+240
-38
lines changed

15 files changed

+240
-38
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
target/
22
.bsp/
3+
.bloop/
4+
.idea/
5+
.metals/
6+
.vscode/

build.sbt

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ import ReleaseTransformations._
22

33
ThisBuild / organization := "com.github.dwickern"
44

5-
lazy val scala213 = "2.13.4"
6-
lazy val scala212 = "2.12.13"
5+
lazy val scala3 = "3.0.2"
6+
lazy val scala213 = "2.13.7"
7+
lazy val scala212 = "2.12.15"
78
lazy val scala211 = "2.11.12"
89

910
lazy val root = project.in(file("."))
1011
.aggregate(nameof.projectRefs: _*)
1112
.enablePlugins(MdocPlugin)
1213
.settings(
1314
// for IntelliJ import: pick one project from the matrix to use
14-
nameof.jvm(scala213).settings,
15+
nameof.jvm(scala3).settings,
1516
target := baseDirectory.value / "target",
1617
ideSkipProject := false,
1718
publish / skip := true,
@@ -25,14 +26,22 @@ lazy val nameof = (projectMatrix in file("."))
2526
releaseCrossBuild := true,
2627
ideSkipProject := true,
2728
libraryDependencies ++= Seq(
28-
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided",
29-
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
30-
"org.scalatest" %%% "scalatest" % "3.2.3" % Test,
31-
"com.chuusai" %% "shapeless" % "2.3.3" % Test,
29+
"org.scalatest" %% "scalatest" % "3.2.10" % Test,
30+
"javax.annotation" % "javax.annotation-api" % "1.3.1" % Test,
3231
),
3332
)
34-
.jsPlatform(scalaVersions = Seq(scala213, scala212, scala211))
35-
.jvmPlatform(scalaVersions = Seq(scala213, scala212, scala211))
33+
.jvmPlatform(scalaVersions = Seq(scala3), Seq(
34+
libraryDependencies ++= Seq(
35+
"org.typelevel" %% "shapeless3-test" % "3.0.4" % Test,
36+
)
37+
))
38+
.jvmPlatform(scalaVersions = Seq(scala213, scala212, scala211), Seq(
39+
libraryDependencies ++= Seq(
40+
"org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided,
41+
"org.scala-lang" % "scala-compiler" % scalaVersion.value % Provided,
42+
"com.chuusai" %% "shapeless" % "2.3.7" % Test,
43+
),
44+
))
3645

3746
Global / excludeLintKeys += ideSkipProject
3847

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version = 1.4.7
1+
sbt.version = 1.5.7

project/plugins.sbt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
logLevel := Level.Warn
22

3-
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.4.0")
4-
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.5")
5-
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.2")
6-
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.13")
7-
addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.7.0")
3+
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.10")
4+
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
5+
addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0")
6+
addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.9.0")
87
addSbtPlugin("org.jetbrains" % "sbt-ide-settings" % "1.1.0")
9-
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.2.17" )
8+
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.2.23" )
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.github.dwickern.macros
2+
3+
import scala.quoted.*
4+
5+
trait NameOf {
6+
/**
7+
* Obtain an identifier name as a constant string.
8+
*
9+
* Example usage:
10+
* {{{
11+
* val amount = 5
12+
* nameOf(amount) => "amount"
13+
* }}}
14+
*/
15+
transparent inline def nameOf(inline expr: Any): String = ${NameOfImpl.nameOf('expr)}
16+
17+
/**
18+
* Obtain an identifier name as a constant string.
19+
*
20+
* This overload can be used to access an instance method without having an instance of the type.
21+
*
22+
* Example usage:
23+
* {{{
24+
* class Person(val name: String)
25+
* nameOf[Person](_.name) => "name"
26+
* }}}
27+
*/
28+
transparent inline def nameOf[T](inline expr: T => Any): String = ${NameOfImpl.nameOf('expr)}
29+
30+
/**
31+
* Obtain a type's unqualified name as a constant string.
32+
*
33+
* Example usage:
34+
* {{{
35+
* nameOfType[String] => "String"
36+
* nameOfType[fully.qualified.ClassName] => "ClassName"
37+
* }}}
38+
*/
39+
transparent inline def nameOfType[T]: String = ${NameOfImpl.nameOfType[T]}
40+
41+
/**
42+
* Obtain a type's qualified name as a constant string.
43+
*
44+
* Example usage:
45+
* {{{
46+
* nameOfType[String] => "java.lang.String"
47+
* nameOfType[fully.qualified.ClassName] => "fully.qualified.ClassName"
48+
* }}}
49+
*/
50+
transparent inline def qualifiedNameOfType[T]: String = ${NameOfImpl.qualifiedNameOfType[T]}
51+
}
52+
object NameOf extends NameOf
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.github.dwickern.macros
2+
3+
import scala.annotation.tailrec
4+
import scala.quoted.*
5+
6+
object NameOfImpl {
7+
def nameOf(expr: Expr[Any])(using Quotes): Expr[String] = {
8+
import quotes.reflect.*
9+
@tailrec def extract(tree: Tree): String = tree match {
10+
case Ident(name) => name
11+
case Select(_, name) => name
12+
case Block(List(stmt), term) => extract(stmt)
13+
case DefDef("$anonfun", _, _, Some(term)) => extract(term)
14+
case Block(_, term) => extract(term)
15+
case Apply(term, _) if term.symbol.fullName != "<special-ops>.throw" => extract(term)
16+
case TypeApply(term, _) => extract(term)
17+
case Inlined(_, _, term) => extract(term)
18+
case Typed(term, _) => extract(term)
19+
case _ => throw new MatchError(s"Unsupported expression: ${expr.show}")
20+
}
21+
val name = extract(expr.asTerm)
22+
Expr(name)
23+
}
24+
25+
def nameOfType[T](using Quotes, Type[T]): Expr[String] = {
26+
import quotes.reflect.*
27+
val name = TypeTree.of[T].tpe.dealias match {
28+
case t @ (AndType(_, _) | OrType(_, _)) => throw new MatchError(s"Unsupported type: ${t.show}")
29+
case t => t.typeSymbol.name
30+
}
31+
val clean = name.stripSuffix("$")
32+
Expr(clean)
33+
}
34+
35+
def qualifiedNameOfType[T](using Quotes, Type[T]): Expr[String] = {
36+
import quotes.reflect.*
37+
val fullName = TypeTree.of[T].tpe.dealias match {
38+
case t @ (AndType(_, _) | OrType(_, _)) => throw new MatchError(s"Unsupported type: ${t.show}")
39+
case t => t.typeSymbol.fullName
40+
}
41+
val clean = fullName
42+
.split('.')
43+
.map(_.stripPrefix("_$").stripSuffix("$"))
44+
.mkString(".")
45+
Expr(clean)
46+
}
47+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.github.dwickern.macros
2+
3+
package object test {
4+
val illTyped = shapeless.test.illTyped
5+
}

0 commit comments

Comments
 (0)