Skip to content

Commit

Permalink
Explicitly passing WeakTypeTags in internals (#465)
Browse files Browse the repository at this point in the history
* bit more of internal Tag APIs exposed

* wip

* wip

* wip

* wip
  • Loading branch information
pshirshov authored May 31, 2024
1 parent b0ed596 commit 87656b6
Showing 1 changed file with 88 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,24 @@ class TagMacro(val c: blackbox.Context) {
final def makeTag[T: c.WeakTypeTag]: c.Expr[Tag[T]] = {
val tpe = weakTypeOf[T]
if (ReflectionUtil.allPartsStrong(tpe.dealias)) {
logger.log(s"Got strong tag, generating LTT right away: ${weakTypeOf[T]}")
val ltag = ltagMacro.makeParsedLightTypeTagImpl(tpe)
val cls = closestClass(tpe)
c.Expr[Tag[T]] {
q"_root_.izumi.reflect.Tag.apply[$tpe]($cls, $ltag)"
}
makeStrongTagImpl[T](tpe, implicitly[c.WeakTypeTag[T]])
} else {
makeTagImpl[T]
makeWeakTagImpl[T](tpe, implicitly[c.WeakTypeTag[T]])
}
}

final def makeStrongTag[T: c.WeakTypeTag]: c.Expr[Tag[T]] = {
val tpe = weakTypeOf[T]
assert(ReflectionUtil.allPartsStrong(tpe.dealias))
makeStrongTagImpl[T](tpe, implicitly[c.WeakTypeTag[T]])
}

final def makeWeakTag[T: c.WeakTypeTag]: c.Expr[Tag[T]] = {
val tpe = weakTypeOf[T]
assert(!ReflectionUtil.allPartsStrong(tpe.dealias))
makeWeakTagImpl[T](tpe, implicitly[c.WeakTypeTag[T]])
}

@inline final def makeHKTagMaterializer[ArgStruct: c.WeakTypeTag]: c.Expr[HKTagMaterializer[ArgStruct]] = {
c.Expr[HKTagMaterializer[ArgStruct]](q"new ${weakTypeOf[HKTagMaterializer[ArgStruct]]}(${makeHKTag[ArgStruct]})")
}
Expand All @@ -68,13 +75,55 @@ class TagMacro(val c: blackbox.Context) {
logger.log(s"HK: found Strong ctor=$ctor in ArgStruct, returning $argStruct")
makeHKTagFromStrongTpe(ctor)
} else {
makeHKTagImpl(ctor)
makeHKTagImpl(ctor, implicitly[c.WeakTypeTag[ArgStruct]])
}
}

private def makeStrongTagImpl[T](tpe: c.Type, tag: c.WeakTypeTag[T]): c.Expr[Tag[T]] = {
logger.log(s"Got strong tag, generating LTT right away: ${tag.tpe}")
val ltag = ltagMacro.makeParsedLightTypeTagImpl(tpe)
val cls = closestClass(tpe)

{
// compiler always inserts WeakTypeTag, by passing it explicitly we slightly reduce fragility
implicit val itag: c.WeakTypeTag[T] = tag
c.Expr[Tag[T]] {
q"_root_.izumi.reflect.Tag.apply[$tpe]($cls, $ltag)"
}
}
}

private def makeWeakTagImpl[T](tpe: c.Type, tag: c.WeakTypeTag[T]): c.Expr[Tag[T]] = {
logger.log(s"Got non-strong tag: $tpe")

if (getImplicitError().endsWith(":")) { // yep
logger.log(s"Got continuation implicit error: ${getImplicitError()}")
} else {
resetImplicitError(tpe)
addImplicitError("\n\n<trace>: ")
}

val tgt = ReflectionUtil.norm(c.universe: c.universe.type, logger)(tpe.dealias)

addImplicitError(s" deriving Tag for $tpe, dealiased: $tgt:")

val res = tgt match {
case RefinedType(intersection, _) =>
mkRefined[T](intersection, tgt, tag)
case _ =>
mkTagWithTypeParameters[T](tgt, tag)
}

addImplicitError(s" succeeded for: $tgt")

logger.log(s"Final code of Tag[$tpe]:\n ${showCode(res.tree)}")

res
}

// FIXME: nearly a copypaste of mkTagWithTypeParameters, deduplicate?
private[this] def makeHKTagImpl[ArgStruct: c.WeakTypeTag](outerLambda: Type): c.Expr[HKTag[ArgStruct]] = {
logger.log(s"Got unresolved HKTag summon: ${tagFormat(outerLambda)} from ArgStruct: ${weakTypeOf[ArgStruct]}")
private[this] def makeHKTagImpl[ArgStruct](outerLambda: Type, tag: c.WeakTypeTag[ArgStruct]): c.Expr[HKTag[ArgStruct]] = {
logger.log(s"Got unresolved HKTag summon: ${tagFormat(outerLambda)} from ArgStruct: ${tag.tpe}")

def isLambdaParamOf(arg: Type, lam: Type): Boolean = {
lam.typeParams.contains(arg.typeSymbol)
Expand Down Expand Up @@ -132,8 +181,12 @@ class TagMacro(val c: blackbox.Context) {
c.Expr[List[Option[LightTypeTag]]](q"$argExprs")
}

reify {
HKTag.appliedTagNonPos[ArgStruct](constructorTag.splice, argTags.splice)
{
// compiler always inserts WeakTypeTag, by passing it explicitly we slightly reduce fragility. quasiquotes implicitly use WTT
implicit val itag: c.WeakTypeTag[ArgStruct] = tag
reify {
HKTag.appliedTagNonPos[ArgStruct](constructorTag.splice, argTags.splice)
}
}
} else {
// warn if constructor is an intersection type, as they don't work properly in this position right now
Expand Down Expand Up @@ -209,9 +262,14 @@ class TagMacro(val c: blackbox.Context) {
}

val outerLambdaReprTag = ltagMacro.makeParsedLightTypeTagImpl(LightTypeTag(ctorApplyingLambda, Map.empty, Map.empty))
reify {
val ctorTag = constructorTag.splice
HKTag.appliedTagNonPosAux[ArgStruct](ctorTag.closestClass, outerLambdaReprTag.splice, Some(ctorTag.tag) :: argTagsExceptCtor.splice)

{
// compiler always inserts WeakTypeTag, by passing it explicitly we slightly reduce fragility. quasiquotes implicitly use WTT
implicit val itag: c.WeakTypeTag[ArgStruct] = tag
reify {
val ctorTag = constructorTag.splice
HKTag.appliedTagNonPosAux[ArgStruct](ctorTag.closestClass, outerLambdaReprTag.splice, Some(ctorTag.tag) :: argTagsExceptCtor.splice)
}
}
}
}
Expand All @@ -229,36 +287,8 @@ class TagMacro(val c: blackbox.Context) {
}
}

def makeTagImpl[T: c.WeakTypeTag]: c.Expr[Tag[T]] = {
logger.log(s"Got non-strong tag: ${weakTypeOf[T]}")

if (getImplicitError().endsWith(":")) { // yep
logger.log(s"Got continuation implicit error: ${getImplicitError()}")
} else {
resetImplicitError(weakTypeOf[T])
addImplicitError("\n\n<trace>: ")
}

val tgt = ReflectionUtil.norm(c.universe: c.universe.type, logger)(weakTypeOf[T].dealias)

addImplicitError(s" deriving Tag for ${weakTypeOf[T]}, dealiased: $tgt:")

val res = tgt match {
case RefinedType(intersection, _) =>
mkRefined[T](intersection, tgt)
case _ =>
mkTagWithTypeParameters[T](tgt)
}

addImplicitError(s" succeeded for: $tgt")

logger.log(s"Final code of Tag[${weakTypeOf[T]}]:\n ${showCode(res.tree)}")

res
}

@inline
protected[this] def mkRefined[T: c.WeakTypeTag](intersection: List[Type], originalRefinement: Type): c.Expr[Tag[T]] = {
protected[this] def mkRefined[T](intersection: List[Type], originalRefinement: Type, tag: c.WeakTypeTag[T]): c.Expr[Tag[T]] = {
val summonedIntersectionTags = intersection.map {
t0 =>
val t = ReflectionUtil.norm(c.universe: c.universe.type, logger)(t0.dealias)
Expand All @@ -268,8 +298,13 @@ class TagMacro(val c: blackbox.Context) {
val (structTag, additionalTypeMembers) = mkStruct(intersection, originalRefinement)
val cls = closestClass(originalRefinement)

reify {
Tag.refinedTag[T](cls.splice, intersectionTags.splice, structTag.splice, additionalTypeMembers.splice)
{
// compiler always inserts WeakTypeTag, by passing it explicitly we slightly reduce fragility
implicit val itag: c.WeakTypeTag[T] = tag
reify {
Tag.refinedTag[T](cls.splice, intersectionTags.splice, structTag.splice, additionalTypeMembers.splice)
}

}
}

Expand Down Expand Up @@ -299,7 +334,7 @@ class TagMacro(val c: blackbox.Context) {

// we need to handle three cases – type args, refined types and type bounds (we don't handle type bounds currently)
@inline
protected[this] def mkTagWithTypeParameters[T: c.WeakTypeTag](tpe: Type): c.Expr[Tag[T]] = {
protected[this] def mkTagWithTypeParameters[T](tpe: Type, tag: c.WeakTypeTag[T]): c.Expr[Tag[T]] = {
val constructorTag: c.Expr[HKTag[_]] = {
val ctor = tpe.typeConstructor
getCtorKindIfCtorIsTypeParameter(ctor) match {
Expand Down Expand Up @@ -346,8 +381,12 @@ class TagMacro(val c: blackbox.Context) {
c.Expr[List[LightTypeTag]](Liftable.liftList[c.Expr[LightTypeTag]].apply(args.map(summonLightTypeTagOfAppropriateKind)))
}

reify {
Tag.appliedTag[T](constructorTag.splice, argTags.splice)
{
// compiler always inserts WeakTypeTag, by passing it explicitly we slightly reduce fragility
implicit val itag: c.WeakTypeTag[T] = tag
reify {
Tag.appliedTag[T](constructorTag.splice, argTags.splice)
}
}
}

Expand Down

0 comments on commit 87656b6

Please sign in to comment.