Generally, typechecking a tree manually and sharing the typed tree among different contexts is a bad idea. See the following example:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
import scala.collection.mutable
object Macros {
  val mtcCache = mutable.Map[whitebox.Context#Type, whitebox.Context#Tree]()
  trait MyTypeclass[A]
  object MyTypeclass {
    implicit def materialize[A]: MyTypeclass[A] = macro materializeImpl[A]
    def materializeImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
      import c.universe._
      val typA = weakTypeOf[A]
      if (!mtcCache.contains(typA)) 
        mtcCache += (typA -> c.typecheck(q"new MyTypeclass[$typA] {}"))
      mtcCache(typA).asInstanceOf[Tree]
    }
  }
}
import Macros.MyTypeclass
object App { // Internal error: unable to find the outer accessor symbol of object App
  class A { // Internal error: unable to find the outer accessor symbol of class A
    class B { // Internal error: unable to find the outer accessor symbol of class A
      class C {
        implicitly[MyTypeclass[Int]] // new MyTypeclass[Int] {} is created and typechecked here
      }
      implicitly[MyTypeclass[Int]] // cached typed instance is inserted here, this is the reason of above error
    }
    implicitly[MyTypeclass[Int]] // cached typed instance is inserted here, this is the reason of above error
  }
  implicitly[MyTypeclass[Int]] // cached typed instance is inserted here, this is the reason of above error
}
Scala 2.13.3.
With implicitly we put in some places trees with incorrect symbol owner chain.
If you make A, B, C objects then errors disappear (so whether this prevents compilation depends on a luck).
Also if you remove c.typecheck then errors disappear.
Also if we return c.untypecheck(mtcCache(typA).asInstanceOf[Tree]) instead of mtcCache(typA).asInstanceOf[Tree] then errors disappear. But sometimes c.typecheck + c.untypecheck can damage a tree.
So you can try to put both untyped and typed versions of a tree to the cache if you need both but return the untyped one
type CTree = whitebox.Context#Tree
val mtcCache = mutable.Map[whitebox.Context#Type, (CTree, CTree)]()
trait MyTypeclass[A]
object MyTypeclass {
  implicit def materialize[A]: MyTypeclass[A] = macro materializeImpl[A]
  def materializeImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
    import c.universe._
    val typA = weakTypeOf[A]
    val tree = q"new MyTypeclass[$typA] {}"
    if (!mtcCache.contains(typA)) 
      mtcCache += (typA -> (tree, c.typecheck(tree)))
    mtcCache(typA)._1.asInstanceOf[Tree]
  }
}
or if you need typechecking only to trigger the recursion then you can typecheck a tree, put the untyped tree to the cache and return the untyped one
val mtcCache = mutable.Map[whitebox.Context#Type, whitebox.Context#Tree]()
trait MyTypeclass[A]
object MyTypeclass {
  implicit def materialize[A]: MyTypeclass[A] = macro materializeImpl[A]
  def materializeImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
    import c.universe._
    val typA = weakTypeOf[A]
    val tree = q"new MyTypeclass[$typA] {}"
    c.typecheck(tree)
    if (!mtcCache.contains(typA)) mtcCache += (typA -> tree)
    mtcCache(typA).asInstanceOf[Tree]
  }
}
Pull request: https://github.com/readren/json-facile/pull/1