Closed
Description
Minimized code
file 1:
package cps
import scala.quoted._
trait CpsMonad[F[_]]
trait ComputationBound[T]
implicit object ComputationBoundMonad extends CpsMonad[ComputationBound]
inline def async[F[_]](using am:CpsMonad[F]): Async.InferAsyncArg[F] =
new Async.InferAsyncArg[F]
object PFHelper {
def create[X,Y](x:Boolean):PartialFunction[X,Y] = ???
}
object Async {
class InferAsyncArg[F[_]](using am:CpsMonad[F]) {
inline def apply[T](inline expr: T):Unit =
${
Async.transformImpl[F,T]('expr)
}
}
def transformImpl[F[_]:Type,T:Type](f: Expr[T])(using qctx: QuoteContext): Expr[Unit] =
import qctx.tasty.{_,given _}
def uninline(t:Term):Term =
t match
case Inlined(_,_,x) => uninline(x)
case _ => t
val fu = uninline(f.unseal)
fu match
case Block(_,Apply(TypeApply(Select(q,n),tparams),List(param))) =>
param.tpe match
case AppliedType(tp,tparams1) =>
val fromTypeOrBounds = tparams1.head
val fromType = fromTypeOrBounds match
case bounds: TypeBounds => bounds.low
case tp: Type => tp
case np: NoPrefix => ???
val toType = tparams1.tail.head
val fType = summon[quoted.Type[F]]
val toWrapped = AppliedType(fType.unseal.tpe,List(toType))
val helper = '{ cps.PFHelper }.unseal
val helperSelect = Select.unique(helper,"create")
val createPF = Apply(
TypeApply(helperSelect,List(Inferred(fromType),Inferred(toWrapped))),
List(Literal(Constant(true)))
)
val createPfApply = Apply(Select.unique(createPF,"apply"),List(Literal(Constant(1))))
Block(List(createPfApply),Literal(Constant(()))).seal.asInstanceOf[Expr[Unit]]
}
file2:
package cps
val c = async[ComputationBound]{
List(1,2,3,4).collectFirst{ case x if x > 0 => x > 3 }
}
Output
[error] |Type argument cps.ComputationBound/T[Boolean/T] does not conform to lower bound Nothing/T
[error] |Constraint(
[error] | uninstVars = ;
[error] | constrained types =
[error] | bounds =
[error] | ordering =
[error] |)
[error] |Subtype trace:
[error] | ==> cps.ComputationBound/T[Boolean/T] <:< Nothing/T
[error] | ==> cps.ComputationBound/T[Boolean/T] <:< Nothing/T recur
[error] | ==> Any/T <:< Nothing/T recur
[error] | <== Any/T <:< Nothing/T recur = false
[error] | <== cps.ComputationBound/T[Boolean/T] <:< Nothing/T recur = false
[error] | <== cps.ComputationBound/T[Boolean/T] <:< Nothing/T = false
[error] | This location contains code that was inlined from TestCBS1ShiftIterableOps.scala:3
Note, that error is about lower-bound Nothing, but type trace shows the opposite.
If we will print an expression in TypeOps:
'compiler/src/dotty/tools/dotc/core/TypeOps.scala'
near line 585 we will see, that violation is created, when
! (loBound <:< hi)
where
loBound=TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),module scala),Nothing),
hi=AppliedType(HKTypeLambda(List(T), List(TypeBounds(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),module scala),Nothing),TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),module scala),Any))), AppliedType(TypeRef(ThisType(TypeRef(NoPrefix,module class cps)),trait ComputationBound),List(TypeParamRef(T)))),List(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Boolean)))
which is quite strange.
(will think, how to pass debug flag into <:< )
Expectation
should be compiled.