Skip to content
Open
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
25 changes: 25 additions & 0 deletions compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,26 @@ private class ExtractDependenciesCollector(rec: DependencyRecorder) extends tpd.
rec.addClassDependency(parent.tpe.classSymbol, depContext)
}

// Only reference DependencyByMacroExpansion if it an be found on the classpath,
// as it was added later to the zinc.apiinfo DependencyContext enum
// e.g. pre 1.10.x sbt would throw java.lang.NoSuchFieldError errors here
lazy val allowsDependencyByMacroExpansion =
classOf[DependencyContext].getFields().exists(_.getName() == "DependencyByMacroExpansion")

private def addMacroDependency(trees: List[Tree])(using Context): Unit =
if (allowsDependencyByMacroExpansion) {
val traverser = new TypeDependencyTraverser {
def addDependency(symbol: Symbol) =
if (!ignoreDependency(symbol)) {
val enclOrModuleClass = if (symbol.is(ModuleVal)) symbol.moduleClass else symbol.enclosingClass
assert(enclOrModuleClass.isClass, s"$enclOrModuleClass, $symbol")

rec.addClassDependency(enclOrModuleClass, DependencyByMacroExpansion)
}
}
trees.foreach(tree => traverser.traverse(tree.tpe))
}

private def depContextOf(cls: Symbol)(using Context): DependencyContext =
if cls.isLocal then LocalDependencyByInheritance
else DependencyByInheritance
Expand Down Expand Up @@ -226,6 +246,11 @@ private class ExtractDependenciesCollector(rec: DependencyRecorder) extends tpd.
case _ =>
}

tree match
case TypeApply(fun, args) if fun.symbol.is(Inline) =>
addMacroDependency(args)
Comment on lines +250 to +251
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this might fix the specific shape of macro like MacWire that lifts the type symbol into a constructor, but I don't think it addresses the larger issue that we're not traversing the generated code, which I tried to fix in #24171.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Realistically I think we need both - some macros might not directly generate the passed type argument in the resulting tree, but may still use it to decide what that tree should be. I'll review your solution later today and then rebase this PR on top of that

case _ =>

tree match {
case tree: Inlined if !tree.inlinedFromOuterScope =>
// The inlined call is normally ignored by TreeTraverser but we need to
Expand Down
2 changes: 1 addition & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,7 @@ object Build {
Compile / scalacOptions ++= Seq("--java-output-version", Versions.minimumJVMVersion),
// Add all the project's external dependencies
libraryDependencies ++= Seq(
("org.scala-sbt" %% "zinc-apiinfo" % "1.8.0" % Test).cross(CrossVersion.for3Use2_13),
("org.scala-sbt" %% "zinc-apiinfo" % "1.10.8" % Test).cross(CrossVersion.for3Use2_13),
"com.github.sbt" % "junit-interface" % "0.13.3" % Test,
),
// Exclude the transitive dependencies from `zinc-apiinfo` that causes issues at the moment
Expand Down
9 changes: 9 additions & 0 deletions sbt-test/macros/i23852/Components.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
object Components extends App {
try {
wire[Dep]
} catch {
case e: Throwable =>
e.printStackTrace()
sys.exit(-1)
}
}
1 change: 1 addition & 0 deletions sbt-test/macros/i23852/Dep.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class Dep()
1 change: 1 addition & 0 deletions sbt-test/macros/i23852/Dep.scala-added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class Dep(int: Int)
16 changes: 16 additions & 0 deletions sbt-test/macros/i23852/macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import scala.quoted.*

inline def wire[T]: T = ${ wireImpl[T] }
def wireImpl[T: Type](using q: Quotes): Expr[T] = {
import q.reflect.*

lazy val targetType = TypeRepr.of[T]
val constructorValue = targetType.typeSymbol.primaryConstructor
val constructionMethodTree: Term = {
val ctor = Select(New(TypeIdent(targetType.typeSymbol)), constructorValue)
if (targetType.typeArgs.isEmpty) ctor else ctor.appliedToTypes(targetType.typeArgs)
}
val constructorArgsValue = List(Nil)
val code: Tree = constructorArgsValue.foldLeft(constructionMethodTree)((acc: Term, args: List[Term]) => Apply(acc, args))
code.asExprOf[T]
}
11 changes: 11 additions & 0 deletions sbt-test/macros/i23852/project/DottyInjectedPlugin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sbt._
import Keys._

object DottyInjectedPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
override def trigger = allRequirements

override val projectSettings = Seq(
scalaVersion := sys.props("plugin.scalaVersion")
)
}
3 changes: 3 additions & 0 deletions sbt-test/macros/i23852/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
> run
$ copy-file Dep.scala-added Dep.scala
-> compile
2 changes: 2 additions & 0 deletions sbt-test/macros/macro-type-change-2/A/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package A
class A
11 changes: 11 additions & 0 deletions sbt-test/macros/macro-type-change-2/app/App.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package app

import Macros.*
import A.A

object App {
@main def hasFields(expected: Boolean): Unit = {
val actual = Macros.hasAnyField[A]
assert(expected == actual, s"Expected $expected, obtained $actual")
}
}
27 changes: 27 additions & 0 deletions sbt-test/macros/macro-type-change-2/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// {
// "projects": [
// {
// "name": "app",
// "dependsOn": [
// "macros",
// "A"
// ],
// "scalaVersion": "2.13.12"
// },
// {
// "name": "macros",
// "scalaVersion": "2.13.12"
// },
// {
// "name": "A",
// "scalaVersion": "2.13.12"
// }
// ]
// }

lazy val app = project.in(file("app"))
.dependsOn(macros, A)

lazy val macros = project.in(file("macros"))

lazy val A = project.in(file("A"))
4 changes: 4 additions & 0 deletions sbt-test/macros/macro-type-change-2/changes/A1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package A
class A {
val hello: String = ""
}
15 changes: 15 additions & 0 deletions sbt-test/macros/macro-type-change-2/macros/Macros.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package Macros

import scala.quoted.*

object Macros {
inline def hasAnyField[T]: Boolean = ${ hasAnyFieldImpl[T] }

def hasAnyFieldImpl[T: Type](using Quotes): Expr[Boolean] = {
import quotes.reflect.*

val hasField = TypeRepr.of[T].typeSymbol.fieldMembers.nonEmpty

Expr(hasField)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sbt._
import Keys._

object DottyInjectedPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
override def trigger = allRequirements

override val projectSettings = Seq(
scalaVersion := sys.props("plugin.scalaVersion")
)
}
4 changes: 4 additions & 0 deletions sbt-test/macros/macro-type-change-2/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# adapted from https://github.com/sbt/zinc/blob/1e422e5525c698aa71cc35b30c275c8c1c3135b2/zinc/src/sbt-test/macros/macro-type-change-2/test
> app/run false
$ copy-file changes/A1.scala A/A.scala
> app/run true
2 changes: 2 additions & 0 deletions sbt-test/macros/macro-type-change-3/A/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package A
class A
2 changes: 2 additions & 0 deletions sbt-test/macros/macro-type-change-3/A/B.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package A
class B extends A
11 changes: 11 additions & 0 deletions sbt-test/macros/macro-type-change-3/app/App.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package app

import Macros.*
import A.B

object App {
@main def hasFields(expected: Boolean): Unit = {
val actual = Macros.hasAnyField[B]
assert(expected == actual, s"Expected $expected, obtained $actual")
}
}
27 changes: 27 additions & 0 deletions sbt-test/macros/macro-type-change-3/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// {
// "projects": [
// {
// "name": "app",
// "dependsOn": [
// "macros",
// "A"
// ],
// "scalaVersion": "2.13.12"
// },
// {
// "name": "macros",
// "scalaVersion": "2.13.12"
// },
// {
// "name": "A",
// "scalaVersion": "2.13.12"
// }
// ]
// }

lazy val app = project.in(file("app"))
.dependsOn(macros, A)

lazy val macros = project.in(file("macros"))

lazy val A = project.in(file("A"))
4 changes: 4 additions & 0 deletions sbt-test/macros/macro-type-change-3/changes/A1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package A
class A {
val hello: String = ""
}
15 changes: 15 additions & 0 deletions sbt-test/macros/macro-type-change-3/macros/Macros.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package Macros

import scala.quoted.*

object Macros {
inline def hasAnyField[T]: Boolean = ${ hasAnyFieldImpl[T] }

def hasAnyFieldImpl[T: Type](using Quotes): Expr[Boolean] = {
import quotes.reflect.*

val hasField = TypeRepr.of[T].typeSymbol.fieldMembers.nonEmpty

Expr(hasField)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sbt._
import Keys._

object DottyInjectedPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
override def trigger = allRequirements

override val projectSettings = Seq(
scalaVersion := sys.props("plugin.scalaVersion")
)
}
4 changes: 4 additions & 0 deletions sbt-test/macros/macro-type-change-3/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# adapted from https://github.com/sbt/zinc/blob/1e422e5525c698aa71cc35b30c275c8c1c3135b2/zinc/src/sbt-test/macros/macro-type-change-3/test
> app/run false
$ copy-file changes/A1.scala A/A.scala
> app/run true
2 changes: 2 additions & 0 deletions sbt-test/macros/macro-type-change-4/A/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package A
class A
11 changes: 11 additions & 0 deletions sbt-test/macros/macro-type-change-4/app/App.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package app

import Macros.*
import A.A

object App {
@main def hasFields(expected: Boolean): Unit = {
val actual = Macros.hasAnyField[A](true)
assert(expected == actual, s"Expected $expected, obtained $actual")
}
}
27 changes: 27 additions & 0 deletions sbt-test/macros/macro-type-change-4/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// {
// "projects": [
// {
// "name": "app",
// "dependsOn": [
// "macros",
// "A"
// ],
// "scalaVersion": "2.13.12"
// },
// {
// "name": "macros",
// "scalaVersion": "2.13.12"
// },
// {
// "name": "A",
// "scalaVersion": "2.13.12"
// }
// ]
// }

lazy val app = project.in(file("app"))
.dependsOn(macros, A)

lazy val macros = project.in(file("macros"))

lazy val A = project.in(file("A"))
4 changes: 4 additions & 0 deletions sbt-test/macros/macro-type-change-4/changes/A1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package A
class A {
val hello: String = ""
}
15 changes: 15 additions & 0 deletions sbt-test/macros/macro-type-change-4/macros/Macros.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package Macros

import scala.quoted.*

object Macros {
inline def hasAnyField[T](placeholder: Boolean): Boolean = ${ hasAnyFieldImpl[T]('placeholder) }

def hasAnyFieldImpl[T: Type](placeholder: Expr[Boolean])(using Quotes): Expr[Boolean] = {
import quotes.reflect.*

val hasField = TypeRepr.of[T].typeSymbol.fieldMembers.nonEmpty

Expr(hasField)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sbt._
import Keys._

object DottyInjectedPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
override def trigger = allRequirements

override val projectSettings = Seq(
scalaVersion := sys.props("plugin.scalaVersion")
)
}
4 changes: 4 additions & 0 deletions sbt-test/macros/macro-type-change-4/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# adapted from https://github.com/sbt/zinc/blob/1e422e5525c698aa71cc35b30c275c8c1c3135b2/zinc/src/sbt-test/macros/macro-type-change-4/test
> app/run false
$ copy-file changes/A1.scala A/A.scala
> app/run true
2 changes: 2 additions & 0 deletions sbt-test/macros/macro-type-change/app/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package app
class A
10 changes: 10 additions & 0 deletions sbt-test/macros/macro-type-change/app/App.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package app

import Macros.*

object App {
@main def hasFields(expected: Boolean): Unit = {
val actual = Macros.hasAnyField[A]
assert(expected == actual, s"Expected $expected, obtained $actual")
}
}
20 changes: 20 additions & 0 deletions sbt-test/macros/macro-type-change/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// {
// "projects": [
// {
// "name": "app",
// "dependsOn": [
// "macros"
// ],
// "scalaVersion": "2.13.12"
// },
// {
// "name": "macros",
// "scalaVersion": "2.13.12"
// }
// ]
// }

lazy val app = project.in(file("app"))
.dependsOn(macros)

lazy val macros = project.in(file("macros"))
4 changes: 4 additions & 0 deletions sbt-test/macros/macro-type-change/changes/A1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package app
class A {
val hello: String = ""
}
15 changes: 15 additions & 0 deletions sbt-test/macros/macro-type-change/macros/Macros.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package Macros

import scala.quoted.*

object Macros {
inline def hasAnyField[T]: Boolean = ${ hasAnyFieldImpl[T] }

def hasAnyFieldImpl[T: Type](using Quotes): Expr[Boolean] = {
import quotes.reflect.*

val hasField = TypeRepr.of[T].typeSymbol.fieldMembers.nonEmpty

Expr(hasField)
}
}
Loading
Loading