<commit_before>/**
* @author ven
*/
package org.jetbrains.plugins.scala
package lang
package psi
package types


import api.base.ScReferenceElement
import com.intellij.openapi.util.Key
import collection.immutable.{Map, HashMap}
import com.intellij.openapi.project.Project
import api.statements.ScTypeAlias
import java.lang.String
import nonvalue.{Parameter, TypeParameter, ScTypePolymorphicType, ScMethodType}
import org.jetbrains.annotations.NotNull
import com.intellij.psi._

object ScSubstitutor {
  val empty = new ScSubstitutor()

  val key: Key[ScSubstitutor] = Key.create("scala substitutor key")
}

class ScSubstitutor(val tvMap: Map[(String, String), ScType],
                    val aliasesMap: Map[String, Suspension[ScType]],
                    val outerMap: Map[PsiClass, Tuple2[ScType, ScReferenceElement]],
                    val dependentMap: Map[PsiClass, PsiNamedElement]) {
  def this() = this (Map.empty, Map.empty, Map.empty, Map.empty)

  def this(tvMap: Map[(String, String), ScType],
                    aliasesMap: Map[String, Suspension[ScType]],
                    outerMap: Map[PsiClass, Tuple2[ScType, ScReferenceElement]]) = {
    this(tvMap, aliasesMap, outerMap, Map.empty)
  }

  def this(tvMap: Map[(String, String), ScType],
                    aliasesMap: Map[String, Suspension[ScType]],
                    outerMap: Map[PsiClass, Tuple2[ScType, ScReferenceElement]],
                    dependentMap: Map[PsiClass, PsiNamedElement], follower: ScSubstitutor) = {
    this(tvMap, aliasesMap, outerMap, dependentMap)
    this.follower = follower
  }

  private var follower: ScSubstitutor = null

  override def toString: String = "ScSubstitutor(" + tvMap + ", " + aliasesMap + ", " + outerMap + ")" +
    (if (follower != null) " followed " + follower.toString else "")

  def bindT(name : (String, String), t: ScType) = {
    /*if (name._1 == "M" && ScType.presentableText(t).startsWith("Nothing[M")) {
      "stop"
    }*/
    new ScSubstitutor(tvMap + ((name, t)), aliasesMap, outerMap, dependentMap, follower)
  }
  def bindA(name: String, t: ScType) =
    new ScSubstitutor(tvMap, aliasesMap + ((name, new Suspension[ScType](t))), outerMap, dependentMap, follower)
  def bindA(name: String, f: () => ScType) =
    new ScSubstitutor(tvMap, aliasesMap + ((name, new Suspension[ScType](f))), outerMap, dependentMap, follower)
  def bindO(outer: PsiClass, t: ScType, ref : ScReferenceElement) =
    new ScSubstitutor(tvMap, aliasesMap, outerMap + ((outer, (t, ref))), dependentMap, follower)
  def bindD(outer: PsiClass, elem: PsiNamedElement) =
    new ScSubstitutor(tvMap, aliasesMap, outerMap, dependentMap + Tuple(outer, elem), follower)
  def incl(s: ScSubstitutor) =
    new ScSubstitutor(s.tvMap ++ tvMap, s.aliasesMap ++ aliasesMap, s.outerMap ++ outerMap, dependentMap, follower)
  def followed(s: ScSubstitutor) : ScSubstitutor = new ScSubstitutor(tvMap, aliasesMap, outerMap, dependentMap,
    if (follower != null) follower followed s else s)

  def subst(t: ScType): ScType = try {
    if (follower != null) follower.subst(substInternal(t)) else substInternal(t)
  }
  catch {
    case s: StackOverflowError =>
      throw new RuntimeException("StackOverFlow during ScSubstitutor.subst(" + t + ") this = " + this, s)
  }

  protected def substInternal(t: ScType) : ScType = t match {
    case f@ScFunctionType(ret, params) => new ScFunctionType(substInternal(ret), params.map(substInternal _),
      f.getProject, f.getScope)
    case t1@ScTupleType(comps) => new ScTupleType(comps map {substInternal _}, t1.getProject)
    case ScProjectionType(proj, element, subst) => new ScProjectionType(substInternal(proj), element, subst)
    case m@ScMethodType(retType, params, isImplicit) => new ScMethodType(substInternal(retType), params.map(p => {
      Parameter(p.name, substInternal(p.paramType), p.isDefault, p.isRepeated)
    }), isImplicit, m.project, m.scope)
    case ScTypePolymorphicType(internalType, typeParameters) => {
      ScTypePolymorphicType(substInternal(internalType), typeParameters.map(tp => {
        TypeParameter(tp.name, substInternal(tp.lowerType), substInternal(tp.upperType), tp.ptp)
      }))
    }

    //todo: ScTypeConstructor
    case tpt : ScTypeParameterType => tvMap.get((tpt.name, tpt.getId)) match {
      case None => tpt
      case Some(v) => v
    }
    case u: ScUndefinedType => tvMap.get((u.tpt.name, u.tpt.getId)) match {<commit_msg>ScSubstitutor optimized<commit_after>/**
* @author ven
*/
package org.jetbrains.plugins.scala
package lang
package psi
package types


import api.base.ScReferenceElement
import com.intellij.openapi.util.Key
import collection.immutable.{Map, HashMap}
import com.intellij.openapi.project.Project
import api.statements.ScTypeAlias
import java.lang.String
import nonvalue.{Parameter, TypeParameter, ScTypePolymorphicType, ScMethodType}
import org.jetbrains.annotations.NotNull
import com.intellij.psi._

object ScSubstitutor {
  val empty = new ScSubstitutor()

  val key: Key[ScSubstitutor] = Key.create("scala substitutor key")
}

class ScSubstitutor(val tvMap: Map[(String, String), ScType],
                    val aliasesMap: Map[String, Suspension[ScType]],
                    val outerMap: Map[PsiClass, Tuple2[ScType, ScReferenceElement]],
                    val dependentMap: Map[PsiClass, PsiNamedElement]) {
  def this() = this (Map.empty, Map.empty, Map.empty, Map.empty)

  def this(tvMap: Map[(String, String), ScType],
                    aliasesMap: Map[String, Suspension[ScType]],
                    outerMap: Map[PsiClass, Tuple2[ScType, ScReferenceElement]]) = {
    this(tvMap, aliasesMap, outerMap, Map.empty)
  }

  def this(tvMap: Map[(String, String), ScType],
                    aliasesMap: Map[String, Suspension[ScType]],
                    outerMap: Map[PsiClass, Tuple2[ScType, ScReferenceElement]],
                    dependentMap: Map[PsiClass, PsiNamedElement], follower: ScSubstitutor) = {
    this(tvMap, aliasesMap, outerMap, dependentMap)
    this.follower = follower
  }

  private var follower: ScSubstitutor = null

  def getFollower: ScSubstitutor = follower

  override def toString: String = "ScSubstitutor(" + tvMap + ", " + aliasesMap + ", " + outerMap + ")" +
    (if (follower != null) " followed " + follower.toString else "")

  def bindT(name : (String, String), t: ScType) = {
    /*if (name._1 == "M" && ScType.presentableText(t).startsWith("Nothing[M")) {
      "stop"
    }*/
    new ScSubstitutor(tvMap + ((name, t)), aliasesMap, outerMap, dependentMap, follower)
  }
  def bindA(name: String, t: ScType) =
    new ScSubstitutor(tvMap, aliasesMap + ((name, new Suspension[ScType](t))), outerMap, dependentMap, follower)
  def bindA(name: String, f: () => ScType) =
    new ScSubstitutor(tvMap, aliasesMap + ((name, new Suspension[ScType](f))), outerMap, dependentMap, follower)
  def bindO(outer: PsiClass, t: ScType, ref : ScReferenceElement) =
    new ScSubstitutor(tvMap, aliasesMap, outerMap + ((outer, (t, ref))), dependentMap, follower)
  def bindD(outer: PsiClass, elem: PsiNamedElement) =
    new ScSubstitutor(tvMap, aliasesMap, outerMap, dependentMap + Tuple(outer, elem), follower)
  def incl(s: ScSubstitutor) =
    new ScSubstitutor(s.tvMap ++ tvMap, s.aliasesMap ++ aliasesMap, s.outerMap ++ outerMap, dependentMap, follower)
  def followed(s: ScSubstitutor): ScSubstitutor = {
    if (follower == null && tvMap.size + aliasesMap.size + outerMap.size + dependentMap.size == 0) return s
    else if (s.getFollower == null && s.tvMap.size + s.outerMap.size + s.aliasesMap.size + s.dependentMap.size == 0) return this
    else return new ScSubstitutor(tvMap, aliasesMap, outerMap, dependentMap,
      if (follower != null) follower followed s else s)
  }

  def subst(t: ScType): ScType = try {
    if (follower != null) follower.subst(substInternal(t)) else substInternal(t)
  }
  catch {
    case s: StackOverflowError =>
      throw new RuntimeException("StackOverFlow during ScSubstitutor.subst(" + t + ") this = " + this, s)
  }

  protected def substInternal(t: ScType) : ScType = t match {
    case f@ScFunctionType(ret, params) => new ScFunctionType(substInternal(ret), params.map(substInternal _),
      f.getProject, f.getScope)
    case t1@ScTupleType(comps) => new ScTupleType(comps map {substInternal _}, t1.getProject)
    case ScProjectionType(proj, element, subst) => new ScProjectionType(substInternal(proj), element, subst)
    case m@ScMethodType(retType, params, isImplicit) => new ScMethodType(substInternal(retType), params.map(p => {
      Parameter(p.name, substInternal(p.paramType), p.isDefault, p.isRepeated)
    }), isImplicit, m.project, m.scope)
    case ScTypePolymorphicType(internalType, typeParameters) => {
      ScTypePolymorphicType(substInternal(internalType), typeParameters.map(tp => {
        TypeParameter(tp.name, substInternal(tp.lowerType), substInternal(tp.upperType), tp.ptp)
      }))
    }

    case tpt : ScTypeParameterType => tvMap.get((tpt.name, tpt.getId)) match {
      case None => tpt
      case Some(v) => v
    }
    case u: ScUndefinedType => tvMap.get((u.tpt.name, u.tpt.getId)) match {
{'fraction_non_alphanumeric': 0.12772006560962273, 'fraction_numerical': 0.0015308911973756151, 'mean_word_length': 4.011506849315069, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 29, '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': '3316034', 'n_tokens_mistral': 3085, 'n_tokens_neox': 2951, 'n_words': 688}