<commit_before>package dotty.tools
package dotc
package typer

import core._
import util.Spans.Span
import Contexts._
import Types._, Flags._, Symbols._, Types._, Names._, StdNames._, Constants._
import TypeErasure.{erasure, hasStableErasure}
import Decorators._
import ProtoTypes._
import Inferencing.{fullyDefinedType, isFullyDefined}
import ast.untpd
import transform.SymUtils._
import transform.TypeUtils._
import transform.SyntheticMembers._
import util.Property
import annotation.{tailrec, constructorOnly}

/** Synthesize terms for special classes */
class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
  import ast.tpd._

  /** Handlers to synthesize implicits for special types */
  type SpecialHandler = (Type, Span) => Context ?=> Tree
  private type SpecialHandlers = List[(ClassSymbol, SpecialHandler)]

  val synthesizedClassTag: SpecialHandler = (formal, span) =>
    formal.argInfos match
      case arg :: Nil =>
        fullyDefinedType(arg, "ClassTag argument", span) match
          case defn.ArrayOf(elemTp) =>
            val etag = typer.inferImplicitArg(defn.ClassTagClass.typeRef.appliedTo(elemTp), span)
            if etag.tpe.isError then EmptyTree else etag.select(nme.wrap)
          case tp if hasStableErasure(tp) && !defn.isBottomClass(tp.typeSymbol) =>
            val sym = tp.typeSymbol
            val classTag = ref(defn.ClassTagModule)
            val tag =
              if sym == defn.UnitClass
                 || sym == defn.AnyClass
                 || sym == defn.AnyValClass
              then
                classTag.select(sym.name.toTermName)
              else
                classTag.select(nme.apply).appliedToType(tp).appliedTo(clsOf(erasure(tp)))
            tag.withSpan(span)
          case tp => EmptyTree
      case _ => EmptyTree
  end synthesizedClassTag

  /** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`.
   *  `T` is deeply dealiased to avoid references to local type aliases.
   */
  val synthesizedTypeTag: SpecialHandler = (formal, span) =>
    def quotedType(t: Type) =
      if StagingContext.level == 0 then
        ctx.compilationUnit.needsStaging = true // We will need to run ReifyQuotes
      val qctx = ctx.typer.inferImplicitArg(defn.QuoteContextClass.typeRef, span)
      qctx.tpe match
        case tpe: Implicits.SearchFailureType => ctx.error(tpe.msg, ctx.source.atSpan(span))
        case _ =>
      ref(defn.InternalQuoted_typeQuote).appliedToType(t).select(nme.apply).appliedTo(qctx)
    formal.argInfos match
      case arg :: Nil =>
        val deepDealias = new TypeMap:
          def apply(tp: Type): Type = mapOver(tp.dealias)
        quotedType(deepDealias(arg))
      case _ =>
        EmptyTree
  end synthesizedTypeTag

  val synthesizedTupleFunction: SpecialHandler = (formal, span) =>
    formal match
      case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
        def functionTypeEqual(baseFun: Type, actualArgs: List[Type],
            actualRet: Type, expected: Type) =
          expected =:= defn.FunctionOf(actualArgs, actualRet,
            defn.isContextFunctionType(baseFun), defn.isErasedFunctionType(baseFun))
        val arity: Int =
          if defn.isErasedFunctionType(fun) || defn.isErasedFunctionType(fun) then -1 // TODO support?
          else if defn.isFunctionType(fun) then
            // TupledFunction[(...) => R, ?]
            fun.dropDependentRefinement.dealias.argInfos match
              case funArgs :+ funRet
              if functionTypeEqual(fun, defn.tupleType(funArgs) :: Nil, funRet, tupled) =>
                // TupledFunction[(...funArgs...) => funRet, ?]
                funArgs.size
              case _ => -1
          else if defn.isFunctionType(tupled) then
            // TupledFunction[?, (...) => R]
            tupled.dropDependentRefinement.dealias.argInfos match
              case tupledArgs :: funRet :: Nil =>
                defn.tupleTypes(tupledArgs.dealias) match
                  case Some(funArgs) if functionTypeEqual(tupled, funArgs, funRet, fun) =>
                    // TupledFunction[?, ((...funArgs...)) => funRet]
                    funArgs.size
                  case _ => -1
              case _ => -1
          else
            // TupledFunction[?, ?]
            -1
        if arity == -1 then
          EmptyTree
        else if arity <= Definitions.MaxImplementedFunctionArity then
          ref(defn.InternalTupleFunctionModule)
            .select(s"tupledFunction$arity".toTermName)
            .appliedToTypes(funArgs)
        else
          ref(defn.InternalTupleFunctionModule)
            .select("tupledFunctionXXL".toTermName)
            .appliedToTypes(funArgs)
      case _ =>
        EmptyTree
  end synthesizedTupleFunction

  /** If `formal` is of the form Eql[T, U], try to synthesize an
    *  `Eql.eqlAny[T, U]` as solution.
    */
  val synthesizedEql: SpecialHandler = (formal, span) =>

    /** Is there an `Eql[T, T]` instance, assuming -strictEquality? */
    def hasEq(tp: Type)(using Context): Boolean =
      val inst = typer.inferImplicitArg(defn.EqlClass.typeRef.appliedTo(tp, tp), span)
      !inst.isEmpty && !inst.tpe.isError

    /** Can we assume the eqlAny instance for `tp1`, `tp2`?
      *  This is the case if assumedCanEqual(tp1, tp2), or
      *  one of `tp1`, `tp2` has a reflexive `Eql` instance.
      */
    def validEqAnyArgs(tp1: Type, tp2: Type)(using Context) =
      typer.assumedCanEqual(tp1, tp2)
       || inContext(ctx.addMode(Mode.StrictEquality)) {
            !hasEq(tp1) && !hasEq(tp2)
          }

    /** Is an `Eql[cls1, cls2]` instance assumed for predefined classes `cls1`, cls2`? */
    def canComparePredefinedClasses(cls1: ClassSymbol, cls2: ClassSymbol): Boolean =

      def cmpWithBoxed(cls1: ClassSymbol, cls2: ClassSymbol) =
        cls2 == defn.boxedType(cls1.typeRef).symbol
        || cls1.isNumericValueClass && cls2.derivesFrom(defn.BoxedNumberClass)

      if cls1.isPrimitiveValueClass then
        if cls2.isPrimitiveValueClass then
          cls1 == cls2 || cls1.isNumericValueClass && cls2.isNumericValueClass
        else
          cmpWithBoxed(cls1, cls2)
      else if cls2.isPrimitiveValueClass then
        cmpWithBoxed(cls2, cls1)
      else if ctx.explicitNulls then
        // If explicit nulls is enabled, we want to disallow comparison between Object and Null.
        // If a nullable value has a non-nullable type, we can still cast it to nullable type
        // then compare.
        //
        // Example:
        // val x: String = null.asInstanceOf[String]
        // if (x == null) {} // error: x is non-nullable
        // if (x.asInstanceOf[String|Null] == null) {} // ok
        cls1 == defn.NullClass && cls1 == cls2
      else if cls1 == defn.NullClass then
        cls1 == cls2 || cls2.derivesFrom(defn.ObjectClass)
      else if cls2 == defn.NullClass then
        cls1.derivesFrom(defn.ObjectClass)
      else
        false
    end canComparePredefinedClasses

    /** Some simulated `Eql` instances for predefined types. It's more efficient
      *  to do this directly instead of setting up a lot of `Eql` instances to
      *  interpret.
      */
    def canComparePredefined(tp1: Type, tp2: Type) =
      tp1.classSymbols.exists(cls1 =>
        tp2.classSymbols.exists(cls2 =>
          canComparePredefinedClasses(cls1, cls2)))

    formal.argTypes match
      case args @ (arg1 :: arg2 :: Nil) =>
        List(arg1, arg2).foreach(fullyDefinedType(_, "eq argument", span))
        if canComparePredefined(arg1, arg2)
            || !Implicits.strictEquality && ctx.test(validEqAnyArgs(arg1, arg2))
        then ref(defn.Eql_eqlAny).appliedToTypes(args).withSpan(span)
        else EmptyTree
      case _ => EmptyTree
  end synthesizedEql

  /** Creates a tree that will produce a ValueOf instance for the requested type.
   * An EmptyTree is returned if materialization fails.
   */
  val synthesizedValueOf: SpecialHandler = (formal, span) =>

    def success(t: Tree) =
      New(defn.ValueOfClass.typeRef.appliedTo(t.tpe), t :: Nil).withSpan(span)

    formal.argInfos match
      case arg :: Nil =>
        fullyDefinedType(arg.dealias, "ValueOf argument", span).normalized match
          case ConstantType(c: Constant) =>
            success(Literal(c))
          case TypeRef(_, sym) if sym == defn.UnitClass =>
            success(Literal(Constant(())))
          case n: TermRef =>
            success(ref(n))
          case tp =>
            EmptyTree
      case _ =>
        EmptyTree
  end synthesizedValueOf

  /** Create an anonymous class `new Object { type MirroredMonoType = ... }`
   *  and mark it with given attachment so that it is made into a mirror at PostTyper.
   */
  private def anonymousMirror(monoType: Type, attachment: Property.StickyKey[Unit], span: Span)(using Context) =
    val monoTypeDef = untpd.TypeDef(tpnme.MirroredMonoType, untpd.TypeTree(monoType))
    val newImpl = untpd.Template(
      constr = untpd.emptyConstructor,
      parents = untpd.TypeTree(defn.ObjectType) :: Nil,
      derived = Nil,
      self = EmptyValDef,
      body = monoTypeDef :: Nil
    ).withAttachment(attachment, ())
    typer.typed(untpd.New(newImpl).withSpan(span))

  /** The mirror type
   *
   *     <parent> {
   *       MirroredMonoType = <monoType>
   *       MirroredType = <mirroredType>
   *       MirroredLabel = <label> }
   *     }
   */
  private def mirrorCore(parentClass: ClassSymbol, monoType: Type, mirroredType: Type, label: Name, formal: Type)(using Context) =
    formal & parentClass.typeRef
      .refinedWith(tpnme.MirroredMonoType, TypeAlias(monoType))
      .refinedWith(tpnme.MirroredType, TypeAlias(mirroredType))
      .refinedWith(tpnme.MirroredLabel, TypeAlias(ConstantType(Constant(label.toString))))

  /** A path referencing the companion of class type `clsType` */
  private def companionPath(clsType: Type, span: Span)(using Context) =
    val ref = pathFor(clsType.companionRef)
    assert(ref.symbol.is(Module) && (clsType.classSymbol.is(ModuleClass) || (ref.symbol.companionClass == clsType.classSymbol)))
    ref.withSpan(span)

  private def checkFormal(formal: Type)(using Context): Boolean =
    @tailrec
    def loop(tp: Type): Boolean = tp match
      case RefinedType(parent, _, _: TypeBounds) => loop(parent)
      case RefinedType(_, _, _) => false
      case _ => true
    loop(formal)

  private def mkMirroredMonoType(mirroredType: HKTypeLambda)(using Context): Type =
    val monoMap = new TypeMap:
      def apply(t: Type) = t match
        case TypeParamRef(lambda, n) if lambda eq mirroredType => mirroredType.paramInfos(n)
        case t => mapOver(t)
    monoMap(mirroredType.resultType)

  private def productMirror(mirroredType: Type, formal: Type, span: Span)(using Context): Tree =
    mirroredType match
      case AndType(tp1, tp2) =>
        productMirror(tp1, formal, span).orElse(productMirror(tp2, formal, span))
      case _ =>
        if mirroredType.termSymbol.is(CaseVal) then
          val module = mirroredType.termSymbol
          val modulePath = pathFor(mirroredType).withSpan(span)
          if module.info.classSymbol.is(Scala2x) then
            val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, module.name, formal)
            val mirrorRef = New(defn.Mirror_SingletonProxyClass.typeRef, modulePath :: Nil)
            mirrorRef.cast(mirrorType)
          else
            val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, module.name, formal)
            modulePath.cast(mirrorType)
        else if mirroredType.classSymbol.isGenericProduct then
          val cls = mirroredType.classSymbol
          val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal))
          val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
          val (monoType, elemsType) = mirroredType match
            case mirroredType: HKTypeLambda =>
              def accessorType(acc: Symbol) =
                acc.info.subst(cls.typeParams, mirroredType.paramRefs)
              val elems =
                mirroredType.derivedLambdaType(
                  resType = TypeOps.nestedPairs(accessors.map(accessorType))
                )
              (mkMirroredMonoType(mirroredType), elems)
            case _ =>
              val elems = TypeOps.nestedPairs(accessors.map(mirroredType.memberInfo(_).widenExpr))
              (mirroredType, elems)
          val mirrorType =
            mirrorCore(defn.Mirror_ProductClass, monoType, mirroredType, cls.name, formal)
              .refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType))
              .refinedWith(tpnme.MirroredElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))<commit_msg>Harden new productMirrorCode to work for erroneous code<commit_after>package dotty.tools
package dotc
package typer

import core._
import util.Spans.Span
import Contexts._
import Types._, Flags._, Symbols._, Types._, Names._, StdNames._, Constants._
import TypeErasure.{erasure, hasStableErasure}
import Decorators._
import ProtoTypes._
import Inferencing.{fullyDefinedType, isFullyDefined}
import ast.untpd
import transform.SymUtils._
import transform.TypeUtils._
import transform.SyntheticMembers._
import util.Property
import annotation.{tailrec, constructorOnly}

/** Synthesize terms for special classes */
class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
  import ast.tpd._

  /** Handlers to synthesize implicits for special types */
  type SpecialHandler = (Type, Span) => Context ?=> Tree
  private type SpecialHandlers = List[(ClassSymbol, SpecialHandler)]

  val synthesizedClassTag: SpecialHandler = (formal, span) =>
    formal.argInfos match
      case arg :: Nil =>
        fullyDefinedType(arg, "ClassTag argument", span) match
          case defn.ArrayOf(elemTp) =>
            val etag = typer.inferImplicitArg(defn.ClassTagClass.typeRef.appliedTo(elemTp), span)
            if etag.tpe.isError then EmptyTree else etag.select(nme.wrap)
          case tp if hasStableErasure(tp) && !defn.isBottomClass(tp.typeSymbol) =>
            val sym = tp.typeSymbol
            val classTag = ref(defn.ClassTagModule)
            val tag =
              if sym == defn.UnitClass
                 || sym == defn.AnyClass
                 || sym == defn.AnyValClass
              then
                classTag.select(sym.name.toTermName)
              else
                classTag.select(nme.apply).appliedToType(tp).appliedTo(clsOf(erasure(tp)))
            tag.withSpan(span)
          case tp => EmptyTree
      case _ => EmptyTree
  end synthesizedClassTag

  /** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`.
   *  `T` is deeply dealiased to avoid references to local type aliases.
   */
  val synthesizedTypeTag: SpecialHandler = (formal, span) =>
    def quotedType(t: Type) =
      if StagingContext.level == 0 then
        ctx.compilationUnit.needsStaging = true // We will need to run ReifyQuotes
      val qctx = ctx.typer.inferImplicitArg(defn.QuoteContextClass.typeRef, span)
      qctx.tpe match
        case tpe: Implicits.SearchFailureType => ctx.error(tpe.msg, ctx.source.atSpan(span))
        case _ =>
      ref(defn.InternalQuoted_typeQuote).appliedToType(t).select(nme.apply).appliedTo(qctx)
    formal.argInfos match
      case arg :: Nil =>
        val deepDealias = new TypeMap:
          def apply(tp: Type): Type = mapOver(tp.dealias)
        quotedType(deepDealias(arg))
      case _ =>
        EmptyTree
  end synthesizedTypeTag

  val synthesizedTupleFunction: SpecialHandler = (formal, span) =>
    formal match
      case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
        def functionTypeEqual(baseFun: Type, actualArgs: List[Type],
            actualRet: Type, expected: Type) =
          expected =:= defn.FunctionOf(actualArgs, actualRet,
            defn.isContextFunctionType(baseFun), defn.isErasedFunctionType(baseFun))
        val arity: Int =
          if defn.isErasedFunctionType(fun) || defn.isErasedFunctionType(fun) then -1 // TODO support?
          else if defn.isFunctionType(fun) then
            // TupledFunction[(...) => R, ?]
            fun.dropDependentRefinement.dealias.argInfos match
              case funArgs :+ funRet
              if functionTypeEqual(fun, defn.tupleType(funArgs) :: Nil, funRet, tupled) =>
                // TupledFunction[(...funArgs...) => funRet, ?]
                funArgs.size
              case _ => -1
          else if defn.isFunctionType(tupled) then
            // TupledFunction[?, (...) => R]
            tupled.dropDependentRefinement.dealias.argInfos match
              case tupledArgs :: funRet :: Nil =>
                defn.tupleTypes(tupledArgs.dealias) match
                  case Some(funArgs) if functionTypeEqual(tupled, funArgs, funRet, fun) =>
                    // TupledFunction[?, ((...funArgs...)) => funRet]
                    funArgs.size
                  case _ => -1
              case _ => -1
          else
            // TupledFunction[?, ?]
            -1
        if arity == -1 then
          EmptyTree
        else if arity <= Definitions.MaxImplementedFunctionArity then
          ref(defn.InternalTupleFunctionModule)
            .select(s"tupledFunction$arity".toTermName)
            .appliedToTypes(funArgs)
        else
          ref(defn.InternalTupleFunctionModule)
            .select("tupledFunctionXXL".toTermName)
            .appliedToTypes(funArgs)
      case _ =>
        EmptyTree
  end synthesizedTupleFunction

  /** If `formal` is of the form Eql[T, U], try to synthesize an
    *  `Eql.eqlAny[T, U]` as solution.
    */
  val synthesizedEql: SpecialHandler = (formal, span) =>

    /** Is there an `Eql[T, T]` instance, assuming -strictEquality? */
    def hasEq(tp: Type)(using Context): Boolean =
      val inst = typer.inferImplicitArg(defn.EqlClass.typeRef.appliedTo(tp, tp), span)
      !inst.isEmpty && !inst.tpe.isError

    /** Can we assume the eqlAny instance for `tp1`, `tp2`?
      *  This is the case if assumedCanEqual(tp1, tp2), or
      *  one of `tp1`, `tp2` has a reflexive `Eql` instance.
      */
    def validEqAnyArgs(tp1: Type, tp2: Type)(using Context) =
      typer.assumedCanEqual(tp1, tp2)
       || inContext(ctx.addMode(Mode.StrictEquality)) {
            !hasEq(tp1) && !hasEq(tp2)
          }

    /** Is an `Eql[cls1, cls2]` instance assumed for predefined classes `cls1`, cls2`? */
    def canComparePredefinedClasses(cls1: ClassSymbol, cls2: ClassSymbol): Boolean =

      def cmpWithBoxed(cls1: ClassSymbol, cls2: ClassSymbol) =
        cls2 == defn.boxedType(cls1.typeRef).symbol
        || cls1.isNumericValueClass && cls2.derivesFrom(defn.BoxedNumberClass)

      if cls1.isPrimitiveValueClass then
        if cls2.isPrimitiveValueClass then
          cls1 == cls2 || cls1.isNumericValueClass && cls2.isNumericValueClass
        else
          cmpWithBoxed(cls1, cls2)
      else if cls2.isPrimitiveValueClass then
        cmpWithBoxed(cls2, cls1)
      else if ctx.explicitNulls then
        // If explicit nulls is enabled, we want to disallow comparison between Object and Null.
        // If a nullable value has a non-nullable type, we can still cast it to nullable type
        // then compare.
        //
        // Example:
        // val x: String = null.asInstanceOf[String]
        // if (x == null) {} // error: x is non-nullable
        // if (x.asInstanceOf[String|Null] == null) {} // ok
        cls1 == defn.NullClass && cls1 == cls2
      else if cls1 == defn.NullClass then
        cls1 == cls2 || cls2.derivesFrom(defn.ObjectClass)
      else if cls2 == defn.NullClass then
        cls1.derivesFrom(defn.ObjectClass)
      else
        false
    end canComparePredefinedClasses

    /** Some simulated `Eql` instances for predefined types. It's more efficient
      *  to do this directly instead of setting up a lot of `Eql` instances to
      *  interpret.
      */
    def canComparePredefined(tp1: Type, tp2: Type) =
      tp1.classSymbols.exists(cls1 =>
        tp2.classSymbols.exists(cls2 =>
          canComparePredefinedClasses(cls1, cls2)))

    formal.argTypes match
      case args @ (arg1 :: arg2 :: Nil) =>
        List(arg1, arg2).foreach(fullyDefinedType(_, "eq argument", span))
        if canComparePredefined(arg1, arg2)
            || !Implicits.strictEquality && ctx.test(validEqAnyArgs(arg1, arg2))
        then ref(defn.Eql_eqlAny).appliedToTypes(args).withSpan(span)
        else EmptyTree
      case _ => EmptyTree
  end synthesizedEql

  /** Creates a tree that will produce a ValueOf instance for the requested type.
   * An EmptyTree is returned if materialization fails.
   */
  val synthesizedValueOf: SpecialHandler = (formal, span) =>

    def success(t: Tree) =
      New(defn.ValueOfClass.typeRef.appliedTo(t.tpe), t :: Nil).withSpan(span)

    formal.argInfos match
      case arg :: Nil =>
        fullyDefinedType(arg.dealias, "ValueOf argument", span).normalized match
          case ConstantType(c: Constant) =>
            success(Literal(c))
          case TypeRef(_, sym) if sym == defn.UnitClass =>
            success(Literal(Constant(())))
          case n: TermRef =>
            success(ref(n))
          case tp =>
            EmptyTree
      case _ =>
        EmptyTree
  end synthesizedValueOf

  /** Create an anonymous class `new Object { type MirroredMonoType = ... }`
   *  and mark it with given attachment so that it is made into a mirror at PostTyper.
   */
  private def anonymousMirror(monoType: Type, attachment: Property.StickyKey[Unit], span: Span)(using Context) =
    val monoTypeDef = untpd.TypeDef(tpnme.MirroredMonoType, untpd.TypeTree(monoType))
    val newImpl = untpd.Template(
      constr = untpd.emptyConstructor,
      parents = untpd.TypeTree(defn.ObjectType) :: Nil,
      derived = Nil,
      self = EmptyValDef,
      body = monoTypeDef :: Nil
    ).withAttachment(attachment, ())
    typer.typed(untpd.New(newImpl).withSpan(span))

  /** The mirror type
   *
   *     <parent> {
   *       MirroredMonoType = <monoType>
   *       MirroredType = <mirroredType>
   *       MirroredLabel = <label> }
   *     }
   */
  private def mirrorCore(parentClass: ClassSymbol, monoType: Type, mirroredType: Type, label: Name, formal: Type)(using Context) =
    formal & parentClass.typeRef
      .refinedWith(tpnme.MirroredMonoType, TypeAlias(monoType))
      .refinedWith(tpnme.MirroredType, TypeAlias(mirroredType))
      .refinedWith(tpnme.MirroredLabel, TypeAlias(ConstantType(Constant(label.toString))))

  /** A path referencing the companion of class type `clsType` */
  private def companionPath(clsType: Type, span: Span)(using Context) =
    val ref = pathFor(clsType.companionRef)
    assert(ref.symbol.is(Module) && (clsType.classSymbol.is(ModuleClass) || (ref.symbol.companionClass == clsType.classSymbol)))
    ref.withSpan(span)

  private def checkFormal(formal: Type)(using Context): Boolean =
    @tailrec
    def loop(tp: Type): Boolean = tp match
      case RefinedType(parent, _, _: TypeBounds) => loop(parent)
      case RefinedType(_, _, _) => false
      case _ => true
    loop(formal)

  private def mkMirroredMonoType(mirroredType: HKTypeLambda)(using Context): Type =
    val monoMap = new TypeMap:
      def apply(t: Type) = t match
        case TypeParamRef(lambda, n) if lambda eq mirroredType => mirroredType.paramInfos(n)
        case t => mapOver(t)
    monoMap(mirroredType.resultType)

  private def productMirror(mirroredType: Type, formal: Type, span: Span)(using Context): Tree =
    mirroredType match
      case AndType(tp1, tp2) =>
        productMirror(tp1, formal, span).orElse(productMirror(tp2, formal, span))
      case _ =>
        if mirroredType.termSymbol.is(CaseVal) then
          val module = mirroredType.termSymbol
          val modulePath = pathFor(mirroredType).withSpan(span)
          if module.info.classSymbol.is(Scala2x) then
            val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, module.name, formal)
            val mirrorRef = New(defn.Mirror_SingletonProxyClass.typeRef, modulePath :: Nil)
            mirrorRef.cast(mirrorType)
          else
            val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, module.name, formal)
            modulePath.cast(mirrorType)
        else if mirroredType.classSymbol.isGenericProduct then
          val cls = mirroredType.classSymbol
          val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal))
          val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
          val (monoType, elemsType) = mirroredType match
            case mirroredType: HKTypeLambda =>
              def accessorType(acc: Symbol) =
                if cls.typeParams.hasSameLengthAs(mirroredType.paramRefs) then
                  acc.info.subst(cls.typeParams, mirroredType.paramRefs)
                else
                  acc.info
              val elems =
                mirroredType.derivedLambdaType(
                  resType = TypeOps.nestedPairs(accessors.map(accessorType))
                )
              (mkMirroredMonoType(mirroredType), elems)
            case _ =>
              val elems = TypeOps.nestedPairs(accessors.map(mirroredType.memberInfo(_).widenExpr))
              (mirroredType, elems)
          val mirrorType =
            mirrorCore(defn.Mirror_ProductClass, monoType, mirroredType, cls.name, formal)
              .refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType))
              .refinedWith(tpnme.MirroredElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))
{'fraction_non_alphanumeric': 0.10377688747131354, 'fraction_numerical': 0.005601151347777043, 'mean_word_length': 2.6267456622936947, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2763423', 'n_tokens_mistral': 7954, 'n_tokens_neox': 7689, 'n_words': 1815}