diff --git a/izumi-reflect/izumi-reflect/src/main/scala-2/izumi/reflect/TagMacro.scala b/izumi-reflect/izumi-reflect/src/main/scala-2/izumi/reflect/TagMacro.scala index e6a2e2e4..ef79471c 100644 --- a/izumi-reflect/izumi-reflect/src/main/scala-2/izumi/reflect/TagMacro.scala +++ b/izumi-reflect/izumi-reflect/src/main/scala-2/izumi/reflect/TagMacro.scala @@ -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]})") } @@ -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: ") + } + + 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) @@ -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 @@ -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) + } } } } @@ -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: ") - } - - 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) @@ -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) + } + } } @@ -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 { @@ -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) + } } }