<commit_before>package dotty.tools
package dotc
package semanticdb

import core.Symbols._
import core.Contexts.Context
import core.Types._
import core.Annotations.Annotation
import core.Flags
import core.Names.Name
import core.StdNames.tpnme
import ast.tpd._

import collection.mutable

import dotty.tools.dotc.{semanticdb => s}

class TypeOps:
  import SymbolScopeOps._
  import Scala3.given
  private val paramRefSymtab = mutable.Map[(LambdaType, Name), Symbol]()
  private val refinementSymtab = mutable.Map[(RefinedType, Name), Symbol]()
  given typeOps: TypeOps = this
  extension (tpe: Type)
    def toSemanticSig(using LinkMode, Context, SemanticSymbolBuilder)(sym: Symbol): s.Signature =
      def enterParamRef(tpe: Type): Unit =
        tpe match {
          case lam: LambdaType =>
            // Find the "actual" binder type for nested LambdaType
            // For example, `def foo(x: T)(y: T): T` and for `<y>.owner.info` would be like
            // `MethodType(...<x>, resType = MethodType(...<y>, resType = <T>))`.
            // (Let's say the outer `MethodType` "outer", and `MethodType` who is
            // `resType` of outer "inner")
            //
            // We try to find the "actual" binder of <y>: `inner`,
            // and register them to the symbol table with `(<y>, inner) -> <y>`
            // instead of `("y", outer) -> <y>`
            if lam.paramNames.contains(sym.name) then
              paramRefSymtab((lam, sym.name)) = sym
            else
              enterParamRef(lam.resType)

          // for class constructor
          // class C[T] { ... }
          case cls: ClassInfo if sym.info.isInstanceOf[LambdaType] =>
            val lam = sym.info.asInstanceOf[LambdaType]
            cls.cls.typeParams.foreach { param =>
              paramRefSymtab((lam, param.name)) = param
            }

          // type X[T] = ...
          case tb: TypeBounds =>
            enterParamRef(tb.lo)
            enterParamRef(tb.hi)

          case _ => ()
        }

      def enterRefined(tpe: Type): Unit =
        tpe match {
          case refined: RefinedType =>
            val key = (refined, sym.name)
            refinementSymtab(key) = sym

          case rec: RecType =>
            enterRefined(rec.parent)

          case cls: ClassInfo
            if (cls.cls.name == tpnme.REFINE_CLASS) =>
            sym.owner.owner.info match {
              // def foo(x: Parent { refinement }) = ...
              case refined: RefinedType =>
                enterRefined(refined)

              // type x = Person { refinement }
              case tb: TypeBounds =>
                // tb = TypeBounds(
                //   lo = RefinedType(...)
                //   hi = RefinedType(...)
                // )
                enterRefined(tb.lo)
                enterRefined(tb.hi)

              // def s(x: Int): { refinement } = ...
              case expr: ExprType =>
                enterRefined(expr.resType)
              case m: MethodType =>
                enterRefined(m.resType)
              case _ => ()
            }
          case _ => ()
        }
      enterParamRef(sym.owner.info)
      enterRefined(sym.owner.info)

      def loop(tpe: Type): s.Signature = tpe match {
        case mp: MethodOrPoly =>
          def flatten(
            t: Type,
            paramss: List[List[Symbol]],
            tparams: List[Symbol]
          ): (Type, List[List[Symbol]], List[Symbol]) = t match {
            case mt: MethodType =>
              val syms = mt.paramNames.flatMap { paramName =>
                val key = (mt, paramName)
                paramRefSymtab.get(key)
              }
              flatten(mt.resType, paramss :+ syms, tparams)
            case pt: PolyType =>
              val syms = pt.paramNames.flatMap { paramName =>
                val key = (pt, paramName)
                paramRefSymtab.get(key)
              }
              // there shouldn't multiple type params
              flatten(pt.resType, paramss, syms)
            case other =>
              (other, paramss, tparams)
          }
          val (resType, paramss, tparams) = flatten(mp, Nil, Nil)

          val sparamss = paramss.map(_.sscope)
          val stparams = Some(tparams.sscope)
          s.MethodSignature(
            stparams,
            sparamss,
            resType.toSemanticType(sym)
          )

        case cls: ClassInfo =>
          val stparams =
            if (cls.cls.typeParams.nonEmpty)
              Some(cls.cls.typeParams.sscope)
            else None
          val sparents = cls.parents.map(_.toSemanticType(sym))
          val sself = cls.selfType.toSemanticType(sym)
          val decls = cls.decls.toList.sscope
          s.ClassSignature(stparams, sparents, sself, Some(decls))

        case TypeBounds(lo, hi) =>
          // for `type X[T] = T` is equivalent to `[T] =>> T`
          def tparams(tpe: Type): (Type, List[Symbol]) = tpe match {
            case lambda: HKTypeLambda =>
              val paramSyms = lambda.paramNames.flatMap { paramName =>
                paramRefSymtab.get((lambda, paramName))
              }
              (lambda.resType, paramSyms)
            case _ => (tpe, Nil)
          }
          val (loRes, loParams) = tparams(lo)
          val (hiRes, hiParams) = tparams(hi)
          val params = (loParams ++ hiParams).distinctBy(_.name)
          val slo = loRes.toSemanticType(sym)
          val shi = hiRes.toSemanticType(sym)
          val stparams = params.sscope
          s.TypeSignature(Some(stparams), slo, shi)

        case other =>
          s.ValueSignature(
            other.toSemanticType(sym)
          )
      }
      loop(tpe)

    private def toSemanticType(using LinkMode, SemanticSymbolBuilder, Context)(sym: Symbol): s.Type =
      import ConstantOps._
      def loop(tpe: Type): s.Type = tpe match {
        case ExprType(tpe) =>
          val stpe = loop(tpe)
          s.ByNameType(stpe)

        case TypeRef(pre, sym: Symbol) =>
          val spre = if(tpe.hasTrivialPrefix) s.Type.Empty else loop(pre)
          val ssym = sym.symbolName
          s.TypeRef(spre, ssym, Seq.empty)

        case TermRef(pre, sym: Symbol) =>
          val spre = if(tpe.hasTrivialPrefix) s.Type.Empty else loop(pre)
          val ssym = sym.symbolName
          s.SingleType(spre, ssym)

        case tref: ParamRef =>
          val key = (tref.binder, tref.paramName)
          paramRefSymtab.get(key) match {
            case Some(ref) =>
              val ssym = ref.symbolName
              tref match {
                case _: TypeParamRef => s.TypeRef(s.Type.Empty, ssym, Seq.empty)
                case _: TermParamRef => s.SingleType(s.Type.Empty, ssym)<commit_msg>Remove unused parameter sym from toSemanticType<commit_after>package dotty.tools
package dotc
package semanticdb

import core.Symbols._
import core.Contexts.Context
import core.Types._
import core.Annotations.Annotation
import core.Flags
import core.Names.Name
import core.StdNames.tpnme
import ast.tpd._

import collection.mutable

import dotty.tools.dotc.{semanticdb => s}

class TypeOps:
  import SymbolScopeOps._
  import Scala3.given
  private val paramRefSymtab = mutable.Map[(LambdaType, Name), Symbol]()
  private val refinementSymtab = mutable.Map[(RefinedType, Name), Symbol]()
  given typeOps: TypeOps = this
  extension (tpe: Type)
    def toSemanticSig(using LinkMode, Context, SemanticSymbolBuilder)(sym: Symbol): s.Signature =
      def enterParamRef(tpe: Type): Unit =
        tpe match {
          case lam: LambdaType =>
            // Find the "actual" binder type for nested LambdaType
            // For example, `def foo(x: T)(y: T): T` and for `<y>.owner.info` would be like
            // `MethodType(...<x>, resType = MethodType(...<y>, resType = <T>))`.
            // (Let's say the outer `MethodType` "outer", and `MethodType` who is
            // `resType` of outer "inner")
            //
            // We try to find the "actual" binder of <y>: `inner`,
            // and register them to the symbol table with `(<y>, inner) -> <y>`
            // instead of `("y", outer) -> <y>`
            if lam.paramNames.contains(sym.name) then
              paramRefSymtab((lam, sym.name)) = sym
            else
              enterParamRef(lam.resType)

          // for class constructor
          // class C[T] { ... }
          case cls: ClassInfo if sym.info.isInstanceOf[LambdaType] =>
            val lam = sym.info.asInstanceOf[LambdaType]
            cls.cls.typeParams.foreach { param =>
              paramRefSymtab((lam, param.name)) = param
            }

          // type X[T] = ...
          case tb: TypeBounds =>
            enterParamRef(tb.lo)
            enterParamRef(tb.hi)

          case _ => ()
        }

      def enterRefined(tpe: Type): Unit =
        tpe match {
          case refined: RefinedType =>
            val key = (refined, sym.name)
            refinementSymtab(key) = sym

          case rec: RecType =>
            enterRefined(rec.parent)

          case cls: ClassInfo
            if (cls.cls.name == tpnme.REFINE_CLASS) =>
            sym.owner.owner.info match {
              // def foo(x: Parent { refinement }) = ...
              case refined: RefinedType =>
                enterRefined(refined)

              // type x = Person { refinement }
              case tb: TypeBounds =>
                // tb = TypeBounds(
                //   lo = RefinedType(...)
                //   hi = RefinedType(...)
                // )
                enterRefined(tb.lo)
                enterRefined(tb.hi)

              // def s(x: Int): { refinement } = ...
              case expr: ExprType =>
                enterRefined(expr.resType)
              case m: MethodType =>
                enterRefined(m.resType)
              case _ => ()
            }
          case _ => ()
        }
      enterParamRef(sym.owner.info)
      enterRefined(sym.owner.info)

      def loop(tpe: Type): s.Signature = tpe match {
        case mp: MethodOrPoly =>
          def flatten(
            t: Type,
            paramss: List[List[Symbol]],
            tparams: List[Symbol]
          ): (Type, List[List[Symbol]], List[Symbol]) = t match {
            case mt: MethodType =>
              val syms = mt.paramNames.flatMap { paramName =>
                val key = (mt, paramName)
                paramRefSymtab.get(key)
              }
              flatten(mt.resType, paramss :+ syms, tparams)
            case pt: PolyType =>
              val syms = pt.paramNames.flatMap { paramName =>
                val key = (pt, paramName)
                paramRefSymtab.get(key)
              }
              // there shouldn't multiple type params
              flatten(pt.resType, paramss, syms)
            case other =>
              (other, paramss, tparams)
          }
          val (resType, paramss, tparams) = flatten(mp, Nil, Nil)

          val sparamss = paramss.map(_.sscope)
          val stparams = Some(tparams.sscope)
          s.MethodSignature(
            stparams,
            sparamss,
            resType.toSemanticType
          )

        case cls: ClassInfo =>
          val stparams =
            if (cls.cls.typeParams.nonEmpty)
              Some(cls.cls.typeParams.sscope)
            else None
          val sparents = cls.parents.map(_.toSemanticType)
          val sself = cls.selfType.toSemanticType
          val decls = cls.decls.toList.sscope
          s.ClassSignature(stparams, sparents, sself, Some(decls))

        case TypeBounds(lo, hi) =>
          // for `type X[T] = T` is equivalent to `[T] =>> T`
          def tparams(tpe: Type): (Type, List[Symbol]) = tpe match {
            case lambda: HKTypeLambda =>
              val paramSyms = lambda.paramNames.flatMap { paramName =>
                paramRefSymtab.get((lambda, paramName))
              }
              (lambda.resType, paramSyms)
            case _ => (tpe, Nil)
          }
          val (loRes, loParams) = tparams(lo)
          val (hiRes, hiParams) = tparams(hi)
          val params = (loParams ++ hiParams).distinctBy(_.name)
          val slo = loRes.toSemanticType
          val shi = hiRes.toSemanticType
          val stparams = params.sscope
          s.TypeSignature(Some(stparams), slo, shi)

        case other =>
          s.ValueSignature(
            other.toSemanticType
          )
      }
      loop(tpe)

    private def toSemanticType(using LinkMode, SemanticSymbolBuilder, Context): s.Type =
      import ConstantOps._
      def loop(tpe: Type): s.Type = tpe match {
        case ExprType(tpe) =>
          val stpe = loop(tpe)
          s.ByNameType(stpe)

        case TypeRef(pre, sym: Symbol) =>
          val spre = if(tpe.hasTrivialPrefix) s.Type.Empty else loop(pre)
          val ssym = sym.symbolName
          s.TypeRef(spre, ssym, Seq.empty)

        case TermRef(pre, sym: Symbol) =>
          val spre = if(tpe.hasTrivialPrefix) s.Type.Empty else loop(pre)
          val ssym = sym.symbolName
          s.SingleType(spre, ssym)

        case tref: ParamRef =>
          val key = (tref.binder, tref.paramName)
          paramRefSymtab.get(key) match {
            case Some(ref) =>
              val ssym = ref.symbolName
              tref match {
                case _: TypeParamRef => s.TypeRef(s.Type.Empty, ssym, Seq.empty)
                case _: TermParamRef => s.SingleType(s.Type.Empty, ssym)
{'fraction_non_alphanumeric': 0.11142580308563763, 'fraction_numerical': 0.0001490646195125587, 'mean_word_length': 1.6439408866995073, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 95, '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': '6715986', 'n_tokens_mistral': 4004, 'n_tokens_neox': 3920, 'n_words': 957}