Port Converted

This commit is contained in:
Eugene Yokota 2021-12-12 01:49:11 -05:00
parent d78c75df39
commit 1ed94bff16
14 changed files with 237 additions and 407 deletions

View File

@ -181,7 +181,7 @@ val scriptedSbtReduxMimaSettings = Def.settings(mimaPreviousArtifacts := Set())
lazy val sbtRoot: Project = (project in file("."))
// .aggregate(nonRoots: _*)
.aggregate(collectionProj)
.aggregate(collectionProj, coreMacrosProj)
.settings(
minimalSettings,
onLoadMessage := {
@ -494,7 +494,7 @@ lazy val testingProj = (project in file("testing"))
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestItemEvent.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestStringEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestStringEvent.copy$default$1"),
//no reason to use
// no reason to use
exclude[DirectMissingMethodProblem]("sbt.JUnitXmlTestsListener.testSuite"),
)
)
@ -787,15 +787,8 @@ lazy val commandProj = (project in file("main-command"))
lazy val coreMacrosProj = (project in file("core-macros"))
.dependsOn(collectionProj)
.settings(
baseSettings :+ (crossScalaVersions := (scala212 :: scala213 :: Nil)),
testedBaseSettings :+ (crossScalaVersions := (scala212 :: scala213 :: Nil)),
name := "Core Macros",
libraryDependencies += {
if (scalaBinaryVersion.value == "3") {
"org.scala-lang" % "scala-compiler" % scala213
} else {
"org.scala-lang" % "scala-compiler" % scalaVersion.value
}
},
SettingKey[Boolean]("exportPipelining") := false,
mimaSettings,
)
@ -1110,7 +1103,8 @@ lazy val serverTestProj = (project in file("server-test"))
|}
""".stripMargin
}
val file = (Test / target).value / "generated" / "src" / "test" / "scala" / "testpkg" / "TestProperties.scala"
val file =
(Test / target).value / "generated" / "src" / "test" / "scala" / "testpkg" / "TestProperties.scala"
IO.write(file, content)
file :: Nil
},
@ -1373,8 +1367,7 @@ lazy val lowerUtilProjects =
lazy val nonRoots = allProjects.map(p => LocalProject(p.id))
ThisBuild / scriptedBufferLog := true
ThisBuild / scriptedPrescripted := { _ =>
}
ThisBuild / scriptedPrescripted := { _ => }
def otherRootSettings =
Seq(
@ -1442,21 +1435,24 @@ def customCommands: Seq[Setting[_]] = Seq(
import extracted._
val sv = get(scalaVersion)
val projs = structure.allProjectRefs
val ioOpt = projs find { case ProjectRef(_, id) => id == "ioRoot"; case _ => false }
val ioOpt = projs find { case ProjectRef(_, id) => id == "ioRoot"; case _ => false }
val utilOpt = projs find { case ProjectRef(_, id) => id == "utilRoot"; case _ => false }
val lmOpt = projs find { case ProjectRef(_, id) => id == "lmRoot"; case _ => false }
val lmOpt = projs find { case ProjectRef(_, id) => id == "lmRoot"; case _ => false }
val zincOpt = projs find { case ProjectRef(_, id) => id == "zincRoot"; case _ => false }
(ioOpt map { case ProjectRef(build, _) => "{" + build.toString + "}/publishLocal" }).toList :::
(utilOpt map { case ProjectRef(build, _) => "{" + build.toString + "}/publishLocal" }).toList :::
(lmOpt map { case ProjectRef(build, _) => "{" + build.toString + "}/publishLocal" }).toList :::
(zincOpt map {
case ProjectRef(build, _) =>
val zincSv = get((ProjectRef(build, "zinc") / scalaVersion))
val csv = get((ProjectRef(build, "compilerBridge") / crossScalaVersions)).toList
(csv flatMap { bridgeSv =>
s"++$bridgeSv" :: ("{" + build.toString + "}compilerBridge/publishLocal") :: Nil
}) :::
List(s"++$zincSv", "{" + build.toString + "}/publishLocal")
(ioOpt map { case ProjectRef(build, _) => "{" + build.toString + "}/publishLocal" }).toList :::
(utilOpt map { case ProjectRef(build, _) =>
"{" + build.toString + "}/publishLocal"
}).toList :::
(lmOpt map { case ProjectRef(build, _) =>
"{" + build.toString + "}/publishLocal"
}).toList :::
(zincOpt map { case ProjectRef(build, _) =>
val zincSv = get((ProjectRef(build, "zinc") / scalaVersion))
val csv = get((ProjectRef(build, "compilerBridge") / crossScalaVersions)).toList
(csv flatMap { bridgeSv =>
s"++$bridgeSv" :: ("{" + build.toString + "}compilerBridge/publishLocal") :: Nil
}) :::
List(s"++$zincSv", "{" + build.toString + "}/publishLocal")
}).getOrElse(Nil) :::
List(s"++$sv", "publishLocal") :::
state

View File

@ -1,338 +1,77 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt.internal.util.appmacro
package sbt.internal.util
package appmacro
import sbt.internal.util.Types.Id
import scala.compiletime.summonInline
import scala.quoted.*
import scala.reflect.TypeTest
import scala.reflect._
import macros._
import ContextUtil.{ DynamicDependencyError, DynamicReferenceError }
object ContextUtil {
final val DynamicDependencyError = "Illegal dynamic dependency"
final val DynamicReferenceError = "Illegal dynamic reference"
/**
* Constructs an object with utility methods for operating in the provided macro context `c`.
* Callers should explicitly specify the type parameter as `c.type` in order to preserve the path
* dependent types.
*/
def apply[C <: blackbox.Context with Singleton](c: C): ContextUtil[C] = new ContextUtil(c: C)
/**
* Helper for implementing a no-argument macro that is introduced via an implicit. This method
* removes the implicit conversion and evaluates the function `f` on the target of the conversion.
*
* Given `myImplicitConversion(someValue).extensionMethod`, where `extensionMethod` is a macro
* that uses this method, the result of this method is `f(<Tree of someValue>)`.
*/
def selectMacroImpl[T: c.WeakTypeTag](
c: blackbox.Context
)(f: (c.Expr[Any], c.Position) => c.Expr[T]): c.Expr[T] = {
import c.universe._
c.macroApplication match {
case s @ Select(Apply(_, t :: Nil), _) => f(c.Expr[Any](t), s.pos)
case a @ Apply(_, t :: Nil) => f(c.Expr[Any](t), a.pos)
case x => unexpectedTree(x)
}
}
def unexpectedTree[C <: blackbox.Context](tree: C#Tree): Nothing =
sys.error("Unexpected macro application tree (" + tree.getClass + "): " + tree)
}
/**
* Utility methods for macros. Several methods assume that the context's universe is a full compiler
* (`scala.tools.nsc.Global`). This is not thread safe due to the underlying Context and related
* data structures not being thread safe. Use `ContextUtil[c.type](c)` to construct.
*/
final class ContextUtil[C <: blackbox.Context](val ctx: C) {
import ctx.universe.{ Apply => ApplyTree, _ }
import internal.decorators._
val powerContext = ctx.asInstanceOf[reflect.macros.runtime.Context]
val global: powerContext.universe.type = powerContext.universe
def callsiteTyper: global.analyzer.Typer = powerContext.callsiteTyper
val initialOwner: Symbol = callsiteTyper.context.owner.asInstanceOf[ctx.universe.Symbol]
lazy val alistType = ctx.typeOf[AList[KList]]
lazy val alist: Symbol = alistType.typeSymbol.companion
lazy val alistTC: Type = alistType.typeConstructor
/** Modifiers for a local val. */
lazy val localModifiers = Modifiers(NoFlags)
def getPos(sym: Symbol) = if (sym eq null) NoPosition else sym.pos
/**
* Constructs a unique term name with the given prefix within this Context. (The current
* implementation uses Context.freshName, which increments
*/
def freshTermName(prefix: String) = TermName(ctx.freshName("$" + prefix))
/**
* Constructs a new, synthetic, local ValDef Type `tpe`, a unique name, Position `pos`, an empty
* implementation (no rhs), and owned by `owner`.
*/
def freshValDef(tpe: Type, pos: Position, owner: Symbol): ValDef = {
val SYNTHETIC = (1 << 21).toLong.asInstanceOf[FlagSet]
val sym = owner.newTermSymbol(freshTermName("q"), pos, SYNTHETIC)
setInfo(sym, tpe)
val vd = internal.valDef(sym, EmptyTree)
vd.setPos(pos)
vd
}
lazy val parameterModifiers = Modifiers(Flag.PARAM)
/**
* Collects all definitions in the tree for use in checkReferences. This excludes definitions in
* wrapped expressions because checkReferences won't allow nested dereferencing anyway.
*/
def collectDefs(
tree: Tree,
isWrapper: (String, Type, Tree) => Boolean
): collection.Set[Symbol] = {
val defs = new collection.mutable.HashSet[Symbol]
// adds the symbols for all non-Ident subtrees to `defs`.
val process = new Traverser {
override def traverse(t: Tree) = t match {
case _: Ident => ()
case ApplyTree(TypeApply(Select(_, nme), tpe :: Nil), qual :: Nil)
if isWrapper(nme.decodedName.toString, tpe.tpe, qual) =>
()
case tree =>
if (tree.symbol ne null) {
defs += tree.symbol
()
}
super.traverse(tree)
}
}
process.traverse(tree)
defs
}
/**
* A reference is illegal if it is to an M instance defined within the scope of the macro call. As
* an approximation, disallow referenced to any local definitions `defs`.
*/
def illegalReference(defs: collection.Set[Symbol], sym: Symbol, mType: Type): Boolean =
sym != null && sym != NoSymbol && defs.contains(sym) && {
sym match {
case m: MethodSymbol => m.returnType.erasure <:< mType
case _ => sym.typeSignature <:< mType
}
}
/**
* A reference is illegal if it is to an M instance defined within the scope of the macro call. As
* an approximation, disallow referenced to any local definitions `defs`.
*/
def illegalReference(defs: collection.Set[Symbol], sym: Symbol): Boolean =
illegalReference(defs, sym, weakTypeOf[Any])
type PropertyChecker = (String, Type, Tree) => Boolean
/**
* A function that checks the provided tree for illegal references to M instances defined in the
* expression passed to the macro and for illegal dereferencing of M instances.
*/
def checkReferences(
defs: collection.Set[Symbol],
isWrapper: PropertyChecker,
mType: Type
): Tree => Unit = {
case s @ ApplyTree(TypeApply(Select(_, nme), tpe :: Nil), qual :: Nil) =>
if (isWrapper(nme.decodedName.toString, tpe.tpe, qual)) {
ctx.error(s.pos, DynamicDependencyError)
}
case id @ Ident(name) if illegalReference(defs, id.symbol, mType) =>
ctx.error(id.pos, DynamicReferenceError + ": " + name)
case _ => ()
}
@deprecated("Use that variant that specifies the M instance types to exclude", since = "1.3.0")
/**
* A function that checks the provided tree for illegal references to M instances defined in the
* expression passed to the macro and for illegal dereferencing of M instances.
*/
def checkReferences(defs: collection.Set[Symbol], isWrapper: PropertyChecker): Tree => Unit =
checkReferences(defs, isWrapper, weakTypeOf[Any])
/**
* Constructs a ValDef with a parameter modifier, a unique name, with the provided Type and with
* an empty rhs.
*/
def freshMethodParameter(tpe: Type): ValDef =
ValDef(parameterModifiers, freshTermName("p"), TypeTree(tpe), EmptyTree)
/** Constructs a ValDef with local modifiers and a unique name. */
def localValDef(tpt: Tree, rhs: Tree): ValDef =
ValDef(localModifiers, freshTermName("q"), tpt, rhs)
/** Constructs a tuple value of the right TupleN type from the provided inputs. */
def mkTuple(args: List[Tree]): Tree =
global.gen.mkTuple(args.asInstanceOf[List[global.Tree]]).asInstanceOf[ctx.universe.Tree]
def setSymbol[_Tree](t: _Tree, sym: Symbol): Unit = {
t.asInstanceOf[global.Tree].setSymbol(sym.asInstanceOf[global.Symbol])
()
}
def setInfo(sym: Symbol, tpe: Type): Unit = {
sym.asInstanceOf[global.Symbol].setInfo(tpe.asInstanceOf[global.Type])
()
}
/** Creates a new, synthetic type variable with the specified `owner`. */
def newTypeVariable(owner: Symbol, prefix: String = "T0"): TypeSymbol =
owner
.asInstanceOf[global.Symbol]
.newSyntheticTypeParam(prefix, 0L)
.asInstanceOf[ctx.universe.TypeSymbol]
/** The type representing the type constructor `[X] X` */
lazy val idTC: Type = {
val tvar = newTypeVariable(NoSymbol)
internal.polyType(tvar :: Nil, refVar(tvar))
}
/** A Type that references the given type variable. */
def refVar(variable: TypeSymbol): Type = variable.toTypeConstructor
/**
* Constructs a new, synthetic type variable that is a type constructor. For example, in type
* Y[L[x]], L is such a type variable.
*/
def newTCVariable(owner: Symbol): TypeSymbol = {
val tc = newTypeVariable(owner)
val arg = newTypeVariable(tc, "x");
tc.setInfo(internal.polyType(arg :: Nil, emptyTypeBounds))
tc
}
/** >: Nothing <: Any */
def emptyTypeBounds: TypeBounds =
internal.typeBounds(definitions.NothingClass.toType, definitions.AnyClass.toType)
/** Creates a new anonymous function symbol with Position `pos`. */
def functionSymbol(pos: Position): Symbol =
callsiteTyper.context.owner
.newAnonymousFunctionValue(pos.asInstanceOf[global.Position])
.asInstanceOf[ctx.universe.Symbol]
def functionType(args: List[Type], result: Type): Type = {
val tpe = global.definitions
.functionType(args.asInstanceOf[List[global.Type]], result.asInstanceOf[global.Type])
tpe.asInstanceOf[Type]
}
/**
* Create a Tree that references the `val` represented by `vd`, copying attributes from
* `replaced`.
*/
def refVal(replaced: Tree, vd: ValDef): Tree =
treeCopy.Ident(replaced, vd.name).setSymbol(vd.symbol)
/**
* Creates a Function tree using `functionSym` as the Symbol and changing `initialOwner` to
* `functionSym` in `body`.
*/
def createFunction(params: List[ValDef], body: Tree, functionSym: Symbol): Tree = {
changeOwner(body, initialOwner, functionSym)
val f = Function(params, body)
setSymbol(f, functionSym)
f
}
def changeOwner(tree: Tree, prev: Symbol, next: Symbol): Unit =
new ChangeOwnerAndModuleClassTraverser(
prev.asInstanceOf[global.Symbol],
next.asInstanceOf[global.Symbol]
).traverse(tree.asInstanceOf[global.Tree])
// Workaround copied from scala/async:can be removed once https://github.com/scala/scala/pull/3179 is merged.
private[this] class ChangeOwnerAndModuleClassTraverser(
oldowner: global.Symbol,
newowner: global.Symbol
) extends global.ChangeOwnerTraverser(oldowner, newowner) {
override def traverse(tree: global.Tree): Unit = {
tree match {
case _: global.DefTree => change(tree.symbol.moduleClass)
case _ =>
}
super.traverse(tree)
}
}
/** Returns the Symbol that references the statically accessible singleton `i`. */
def singleton[T <: AnyRef with Singleton](i: T)(implicit it: ctx.TypeTag[i.type]): Symbol =
it.tpe match {
case SingleType(_, sym) if !sym.isFreeTerm && sym.isStatic => sym
case x => sys.error("Instance must be static (was " + x + ").")
}
def select(t: Tree, name: String): Tree = Select(t, TermName(name))
/** Returns the symbol for the non-private method named `name` for the class/module `obj`. */
def method(obj: Symbol, name: String): Symbol = {
val ts: Type = obj.typeSignature
val m: global.Symbol = ts.asInstanceOf[global.Type].nonPrivateMember(global.newTermName(name))
m.asInstanceOf[Symbol]
}
trait ContextUtil[C <: Quotes & scala.Singleton](val qctx: C):
import qctx.reflect.*
given qctx.type = qctx
/**
* Returns a Type representing the type constructor tcp.<name>. For example, given `object Demo {
* type M[x] = List[x] }`, the call `extractTC(Demo, "M")` will return a type representing the
* type constructor `[x] List[x]`.
* type M[x] = List[x] }`, the call `extractTypeCon(Demo, "M")` will return a type representing
* the type constructor `[x] List[x]`.
*/
def extractTC(tcp: AnyRef with Singleton, name: String)(implicit
it: ctx.TypeTag[tcp.type]
): ctx.Type = {
val itTpe = it.tpe.asInstanceOf[global.Type]
val m = itTpe.nonPrivateMember(global.newTypeName(name))
val tc = itTpe.memberInfo(m).asInstanceOf[ctx.universe.Type]
assert(tc != NoType && tc.takesTypeArgs, "Invalid type constructor: " + tc)
tc
}
def extractTypeCon(tcp: AnyRef & scala.Singleton, name: String)(using
tcpt: Type[tcp.type]
): TypeRepr =
val tcpTpe = TypeRepr.of[tcp.type]
val fSym = tcpTpe.typeSymbol.declaredType(name).head
val typeConTpe: TypeRepr = tcpTpe.memberType(fSym)
val hiRepr = typeConTpe match
case TypeBounds(low, TypeLambda(_, _, AppliedType(tc, _))) => tc
hiRepr
/**
* Substitutes wrappers in tree `t` with the result of `subWrapper`. A wrapper is a Tree of the
* form `f[T](v)` for which isWrapper(<Tree of f>, <Underlying Type>, <qual>.target) returns true.
* Typically, `f` is a `Select` or `Ident`. The wrapper is replaced with the result of
* `subWrapper(<Type of T>, <Tree of v>, <wrapper Tree>)`
* Returns a reference given a singleton/termref
*/
def transformWrappers(
t: Tree,
subWrapper: (String, Type, Tree, Tree) => Converted[ctx.type]
): Tree = {
// the main tree transformer that replaces calls to InputWrapper.wrap(x) with
// plain Idents that reference the actual input value
object appTransformer extends Transformer {
override def transform(tree: Tree): Tree =
tree match {
case ApplyTree(TypeApply(Select(_, nme), targ :: Nil), qual :: Nil) =>
subWrapper(nme.decodedName.toString, targ.tpe, qual, tree) match {
case Converted.Success(t, finalTx) =>
changeOwner(
qual,
currentOwner,
initialOwner
) // Fixes https://github.com/sbt/sbt/issues/1150
finalTx(t)
case Converted.Failure(p, m) => ctx.abort(p, m)
case _: Converted.NotApplicable[_] => super.transform(tree)
}
case _ => super.transform(tree)
}
}
appTransformer.atOwner(initialOwner) {
appTransformer.transform(t)
}
}
}
def extractSingleton[A: Type]: Expr[A] =
def termRef(r: TypeRepr)(using rtt: TypeTest[TypeRepr, TermRef]): Ref = r match
case rtt(ref) => Ref.term(ref)
case _ => sys.error(s"expected termRef but got $r")
termRef(TypeRepr.of[A]).asExprOf[A]
private var counter: Int = -1
def freshName(prefix: String): String =
counter = counter + 1
s"$$${prefix}${counter}"
/**
* Constructs a new, synthetic, local var with type `tpe`, a unique name, initialized to
* zero-equivalent (Zero[A]), and owned by `parent`.
*/
def freshValDef(parent: Symbol, tpe: TypeRepr, rhs: Term): ValDef =
tpe.asType match
case '[a] =>
val sym =
Symbol.newVal(
parent,
freshName("q"),
tpe,
Flags.Synthetic,
Symbol.noSymbol
)
ValDef(sym, rhs = Some(rhs))
def typed[A: Type](value: Term): Term =
Typed(value, TypeTree.of[A])
def tupleTypeRepr(param: List[TypeRepr]): TypeRepr =
param match
case x :: xs => TypeRepr.of[scala.*:].appliedTo(List(x, tupleTypeRepr(xs)))
case Nil => TypeRepr.of[EmptyTuple]
final class Input(
val tpe: TypeRepr,
val term: Term,
val name: String
)
trait TermTransform[F[_]]:
def apply(in: Term): Term
end TermTransform
def idTransform: TermTransform[Id] = in => in
end ContextUtil

View File

@ -5,47 +5,75 @@
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt.internal.util
package appmacro
package sbt.internal.util.appmacro
import scala.reflect._
import macros._
import Types.idFun
import sbt.internal.util.Types
import scala.quoted.*
abstract class Convert {
def apply[T: c.WeakTypeTag](c: blackbox.Context)(nme: String, in: c.Tree): Converted[c.type]
def asPredicate(c: blackbox.Context): (String, c.Type, c.Tree) => Boolean =
(n, tpe, tree) => {
val tag = c.WeakTypeTag(tpe)
apply(c)(n, tree)(tag).isSuccess
}
}
sealed trait Converted[C <: blackbox.Context with Singleton] {
def isSuccess: Boolean
def transform(f: C#Tree => C#Tree): Converted[C]
}
object Converted {
def NotApplicable[C <: blackbox.Context with Singleton] = new NotApplicable[C]
final case class Failure[C <: blackbox.Context with Singleton](
position: C#Position,
message: String
) extends Converted[C] {
def isSuccess = false
def transform(f: C#Tree => C#Tree): Converted[C] = new Failure(position, message)
}
final class NotApplicable[C <: blackbox.Context with Singleton] extends Converted[C] {
def isSuccess = false
def transform(f: C#Tree => C#Tree): Converted[C] = this
}
final case class Success[C <: blackbox.Context with Singleton](
tree: C#Tree,
finalTransform: C#Tree => C#Tree
) extends Converted[C] {
def isSuccess = true
def transform(f: C#Tree => C#Tree): Converted[C] = Success(f(tree), finalTransform)
}
object Success {
def apply[C <: blackbox.Context with Singleton](tree: C#Tree): Success[C] =
Success(tree, idFun)
}
}
/**
* Convert is a glorified partial function to scan through the AST for the purpose of substituting
* the matching term with something else.
*
* This is driven by calling transformWrappers(...) method. The filtering is limited to the shape of
* code matched using `appTransformer`, which is a generic function with a single type param and a
* single term param like `X.wrapInit[A](...)`.
*/
trait Convert[C <: Quotes & Singleton](override val qctx: C) extends ContextUtil[C]:
// with TupleBuilder[C]:
import qctx.reflect.*
def convert[A: Type](nme: String, in: Term): Converted
def asPredicate[A]: (String, Type[A], Term) => Boolean =
(n, tpe, tree) =>
val tag = tpe
convert(n, tree)(tag).isSuccess
/**
* Substitutes wrappers in tree `t` with the result of `subWrapper`. A wrapper is a Tree of the
* form `f[T](v)` for which isWrapper(<Tree of f>, <Underlying Type>, <qual>.target) returns true.
* Typically, `f` is a `Select` or `Ident`. The wrapper is replaced with the result of
* `subWrapper(<Type of T>, <Tree of v>, <wrapper Tree>)`
*/
def transformWrappers(
tree: Term,
subWrapper: (String, TypeRepr, Term, Term) => Converted,
owner: Symbol,
): Term =
// the main tree transformer that replaces calls to InputWrapper.wrap(x) with
// plain Idents that reference the actual input value
object appTransformer extends TreeMap:
override def transformTerm(tree: Term)(owner: Symbol): Term =
tree match
case Apply(TypeApply(Select(_, nme), targ :: Nil), qual :: Nil) =>
subWrapper(nme, targ.tpe, qual, tree) match
case Converted.Success(tree, finalTransform) =>
finalTransform(tree)
case Converted.Failure(position, message) =>
report.error(message, position)
sys.error("macro error: " + message)
case _ =>
super.transformTerm(tree)(owner)
case _ =>
super.transformTerm(tree)(owner)
end appTransformer
appTransformer.transformTerm(tree)(owner)
object Converted:
def success(tree: Term) = Converted.Success(tree, Types.idFun)
enum Converted:
def isSuccess: Boolean = this match
case Success(_, _) => true
case _ => false
def transform(f: Term => Term): Converted = this match
case Success(tree, finalTransform) => Success(f(tree), finalTransform)
case x: Failure => x
case x: NotApplicable => x
case Success(tree: Term, finalTransform: Term => Term) extends Converted
case Failure(position: Position, message: String) extends Converted
case NotApplicable() extends Converted
end Converted
end Convert

View File

@ -0,0 +1,15 @@
package sbt.internal
import sbt.internal.util.appmacro.*
import verify.*
import ConvertTestMacro._
object ConvertTest extends BasicTestSuite:
test("convert") {
// assert(someMacro(ConvertTest.wrapInit(1) == 2))
assert(someMacro(ConvertTest.wrapInit(1).toString == "Some(2)"))
}
def wrapInitTask[A](a: A): Int = 2
def wrapInit[A](a: A): Int = 2
end ConvertTest

View File

@ -0,0 +1,42 @@
package sbt.internal
import sbt.internal.util.appmacro.*
import scala.quoted.*
object ConvertTestMacro:
final val WrapInitName = "wrapInit"
final val WrapInitTaskName = "wrapInitTask"
inline def someMacro(inline expr: Boolean): Boolean =
${ someMacroImpl('expr) }
def someMacroImpl(expr: Expr[Boolean])(using qctx: Quotes) =
val convert1: Convert[qctx.type] = new InputInitConvert(qctx)
import convert1.qctx.reflect.*
def addTypeCon(tpe: TypeRepr, qual: Term, selection: Term): Term =
tpe.asType match
case '[a] =>
'{
Option[a](${ selection.asExprOf[a] })
}.asTerm
def substitute(name: String, tpe: TypeRepr, qual: Term, replace: Term) =
convert1.convert[Boolean](name, qual) transform { (tree: Term) =>
addTypeCon(tpe, tree, replace)
}
convert1.transformWrappers(expr.asTerm, substitute, Symbol.spliceOwner).asExprOf[Boolean]
class InputInitConvert[C <: Quotes & scala.Singleton](override val qctx: C)
extends Convert[C](qctx)
with ContextUtil[C](qctx):
// with TupleBuilder[C](qctx)
// with TupleNBuilder[C](qctx):
import qctx.reflect.*
def convert[A: Type](nme: String, in: Term): Converted =
nme match
case WrapInitName => Converted.success(in)
case WrapInitTaskName => Converted.Failure(in.pos, initTaskErrorMessage)
case _ => Converted.NotApplicable()
private def initTaskErrorMessage = "Internal sbt error: initialize+task wrapper not split"
end InputInitConvert
end ConvertTestMacro

View File

@ -7,11 +7,12 @@
package sbt.internal.util
/*
trait TypeFunctions {
import TypeFunctions._
trait TypeFunctions:
type Id[X] = X
type NothingK[X] = Nothing
/*
import TypeFunctions._
sealed trait Const[A] { type Apply[B] = A }
sealed trait ConstK[A] { type l[L[x]] = A }
sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
@ -24,8 +25,10 @@ trait TypeFunctions {
final val right: Id ~> Right[Nothing, *] =
λ[Id ~> AnyRight](Right(_)).setToString("TypeFunctions.right")
final val some: Id ~> Some[*] = λ[Id ~> Some](Some(_)).setToString("TypeFunctions.some")
final def idFun[T]: T => T = ((t: T) => t).setToString("TypeFunctions.id")
final def const[A, B](b: B): A => B = ((_: A) => b).setToString(s"TypeFunctions.const($b)")
*/
final def idFun[A]: A => A = ((a: A) => a) // .setToString("TypeFunctions.id")
final def const[A, B](b: B): A => B = ((_: A) => b) // .setToString(s"TypeFunctions.const($b)")
/*
final def idK[M[_]]: M ~> M = λ[M ~> M](m => m).setToString("TypeFunctions.idK")
def nestCon[M[_], N[_], G[_]](f: M ~> N): (M G)#l ~> (N G)#l =
@ -35,9 +38,13 @@ trait TypeFunctions {
type Endo[T] = T => T
type ~>|[A[_], B[_]] = A ~> Compose[Option, B]#Apply
}
*/
end TypeFunctions
/*
object TypeFunctions extends TypeFunctions:
object TypeFunctions extends TypeFunctions {
private implicit class Ops[T[_], R[_]](val underlying: T ~> R) extends AnyVal {
def setToString(string: String): T ~> R = new (T ~> R) {
override def apply[U](a: T[U]): R[U] = underlying(a)
@ -54,7 +61,8 @@ object TypeFunctions extends TypeFunctions {
override def hashCode: Int = f.hashCode
}
}
}
end TypeFunctions
*/
/*

View File

@ -7,10 +7,12 @@
package sbt.internal.util
object Types extends Types
object Types extends TypeFunctions
trait Types /* extends TypeFunctions */ {
/*
trait Types extends TypeFunctions {
// val :^: = KCons
// type :+:[H, T <: HList] = HCons[H, T]
// val :+: = HCons
}
*/