Closed
Description
Minimized code
X.scala:
package x
import scala.quoted._
trait CB[T]
trait M[F[_]] {
def pure[T](x:T):F[T]
}
object MCB extends M[CB] {
def pure[T](x:T):CB[T] = ???
}
given M[CB] = MCB
object X {
inline def shift[F[_],A,B](inline f: PartialFunction[A,B] )(using M[F]) : A => F[B] = ${
shiftImpl[F,A,B]('f)
}
def shiftImpl[F[_]:Type,A:Type, B:Type](f:Expr[PartialFunction[A,B]])(using qctx: QuoteContext):Expr[A => F[B]] = {
import qctx.tasty._
shiftTerm[F,A,B](using qctx)(f.unseal)
}
def shiftTerm[F[_]:Type,A:Type, B:Type](using qctx: QuoteContext)(f:qctx.tasty.Term):Expr[A => F[B]] = {
import qctx.tasty._
def castTerm[T](x:Term, xt: quoted.Type[T]):Expr[T] =
given quoted.Type[T] = xt
x.seal.cast[T]
def unAnnotate(x:Type):Type =
x match
case AnnotatedType(tp,_) => tp
case _ => x
val mcb = Expr.summon[M[F]].get.unseal
val fTypeTree = summon[quoted.Type[F]].unseal
val partialFunctionType = TypeIdent(Symbol.classSymbol("scala.PartialFunction")).tpe
f match
case Lambda(params, Match(scr,caseDefs)) =>
unAnnotate(f.tpe) match
case AppliedType(tp,tparams) =>
if (tp <:< partialFunctionType)
val (tInBounds, tOutBounds) = tparams match
case tIn::tOut::Nil => (tIn, tOut)
case _ => ???
val tIn = tInBounds match
case TypeBounds(lo,hi) => hi
case tpIn: Type => tpIn
val tOutInMonad = AppliedType(fTypeTree.tpe, List(tOutBounds))
(tIn.seal, tOutInMonad.seal) match
case ( '[$nt], '[$tt] ) =>
val f1 = '{ (v: $nt) => ${
val nTree = Match(scr, caseDefs.map( x =>
CaseDef(x.pattern, x.guard,
Apply(
TypeApply(Select.unique(mcb,"pure"),List(Inferred(x.rhs.tpe))),
List(x.rhs))
) )
)
println(s"beforeCast, tt = ${tt.unseal}, tree.tpe=${nTree.tpe}")
val r = castTerm(nTree, tt)
println("afterCast")
r
}
}
// in real world A and B is not accessible here
f1.cast[A => F[B]]
else
println(s"partialFunction was expected, we have ${f.tpe}")
???
case Inlined(_,List(),x) => shiftTerm[F,A,B](using qctx)(x)
case _ => println(s"Lambda was expected, we have ${f}")
???
}
}
and
Main.scala
package x
object Main {
X.shift[CB,Int,Int]({ case x if x > 1 => x+10 })
}
Output
info] welcome to sbt 1.3.13 (N/A Java 14.0.1)
[info] loading settings for project cast1-build from plugins.sbt ...
[info] loading project definition from /Users/rssh/tests/dotty/cast1/project
Fetching latest Dotty nightly version...
Latest Dotty nightly build version: 0.27.0-bin-20200807-dfcc0b1-NIGHTLY
[info] loading settings for project root from build.sbt ...
[info] set current project to test (in build file:/Users/rssh/tests/dotty/cast1/)
[info] Compiling 2 Scala sources to /Users/rssh/tests/dotty/cast1/target/scala-0.27/classes ...
beforeCast, tt = TypeTree[AppliedType(HKTypeLambda(List(T), List(TypeBounds(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Nothing),TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Any))), AppliedType(TypeRef(ThisType(TypeRef(NoPrefix,module class x)),trait CB),List(TypeParamRef(T)))),List(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),module scala),class Int)))], tree.tpe=AppliedType(TypeRef(ThisType(TypeRef(NoPrefix,module class x)),trait CB),List(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Int)))
[error] -- Error: /Users/rssh/tests/dotty/cast1/src/main/scala/x/Main.scala:6:1 --------
[error] 6 | X.shift[CB,Int,Int]({ case x if x > 1 => x+10 })
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] |Exception occurred while executing macro expansion.
[error] |scala.tasty.reflect.ExprCastError: Expr: (x$1: @scala.unchecked) match {
[error] | case x if x.>(1) =>
[error] | x.given_M_CB.pure[scala.Int](x.+(10))
[error] |}
[error] |did not conform to type: ([T >: scala.Nothing <: scala.Any] => x.CB[T])[scala.Int]
[error] |
[error] | at scala.quoted.Expr.cast(Expr.scala:52)
[error] | at x.X$.castTerm$1(X.scala:37)
[error] | at x.X$.$anonfun$9$2$$anonfun$1(X.scala:71)
[error] | at dotty.tools.dotc.core.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:84)
[error] | at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1306)
[error] | at dotty.tools.dotc.core.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:108)
[error] | at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1286)
[error] | at dotty.tools.dotc.core.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:108)
[error] | at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1345)
[error] | at dotty.tools.dotc.core.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:108)
[error] | at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform$$anonfun$2(Trees.scala:1371)
[error] | at scala.collection.immutable.List.mapConserve(List.scala:472)
[error] | at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1371)
[error] | at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transformStats(Trees.scala:1369)
[error] | at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1286)
[error] | at dotty.tools.dotc.core.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:108)
[error] | at dotty.tools.dotc.core.quoted.PickledQuotes$.spliceTerms(PickledQuotes.scala:123)
[error] | at dotty.tools.dotc.core.quoted.PickledQuotes$.unpickleExpr(PickledQuotes.scala:61)
[error] | at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.unpickleExpr(ReflectionCompilerInterface.scala:40)
[error] | at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.unpickleExpr(ReflectionCompilerInterface.scala:39)
[error] | at scala.internal.quoted.Unpickler$.unpickleExpr(Unpickler.scala:16)
[error] | at x.X$.shiftTerm(X.scala:62)
[error] | at x.X$.shiftImpl(X.scala:29)
[error] |
[error] | This location contains code that was inlined from Main.scala:6
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 4 s, completed 8 Aug 2020, 14:16:44
Expectation
should compiled