<commit_before>package org.jetbrains.plugins.scala.lang.psi.implicits

import org.jetbrains.plugins.scala.lang.psi.ScalaPsiUtil
import org.jetbrains.plugins.scala.lang.psi.api.InferUtil.functionTypeNoImplicits
import org.jetbrains.plugins.scala.lang.psi.api.statements.ScFunction
import org.jetbrains.plugins.scala.lang.psi.api.statements.params.ScParameter
import org.jetbrains.plugins.scala.lang.psi.implicits.NonValueFunctionTypes._
import org.jetbrains.plugins.scala.lang.psi.types.ScType
import org.jetbrains.plugins.scala.lang.psi.types.api.{TypeParameter, UndefinedType}
import org.jetbrains.plugins.scala.lang.psi.types.api.designator.{ScDesignatorType, ScProjectionType}
import org.jetbrains.plugins.scala.lang.psi.types.nonvalue.{ScMethodType, ScTypePolymorphicType}
import org.jetbrains.plugins.scala.lang.psi.types.recursiveUpdate.ScSubstitutor
import org.jetbrains.plugins.scala.macroAnnotations.Measure

import scala.collection.Set

private case class NonValueFunctionTypes(fun: ScFunction, substitutor: ScSubstitutor, typeFromMacro: Option[ScType]) {

  private lazy val undefinedData: Option[UndefinedTypeData] = computeUndefinedType(fun, substitutor, typeFromMacro)

  private lazy val methodTypeData: Option[MethodTypeData] =
    undefinedData.flatMap(computeMethodType(fun, substitutor, _))

  def undefinedType: Option[ScType] = undefinedData.map(_.undefinedType)

  def hadDependents: Boolean = undefinedData.exists(_.hadDependent)

  def methodType: Option[ScType] = methodTypeData.map(_.methodType)

  def hasImplicitClause: Boolean = methodTypeData.exists(_.hasImplicitClause)
}

private object NonValueFunctionTypes {

  private case class UndefinedTypeData(undefinedType: ScType, hadDependent: Boolean)

  private case class MethodTypeData(methodType: ScType, hasImplicitClause: Boolean)

  @Measure
  private def computeMethodType(fun: ScFunction,
                                substitutor: ScSubstitutor,
                                undefinedTypeData: UndefinedTypeData): Option[MethodTypeData] = {

    val typeParameters = fun.typeParameters
    val implicitClause = fun.effectiveParameterClauses.lastOption.filter(_.isImplicit)

    if (typeParameters.isEmpty && implicitClause.isEmpty) {
      None
    } else {
      val undefinedReturnType = undefinedTypeData.undefinedType

      val methodOrReturnType = implicitClause match {
        case None => undefinedReturnType
        case Some(clause) =><commit_msg>use non-synchronized lazy initialization in NonValueFunctionTypes<commit_after>package org.jetbrains.plugins.scala.lang.psi.implicits

import org.jetbrains.plugins.scala.lang.psi.ScalaPsiUtil
import org.jetbrains.plugins.scala.lang.psi.api.InferUtil.functionTypeNoImplicits
import org.jetbrains.plugins.scala.lang.psi.api.statements.ScFunction
import org.jetbrains.plugins.scala.lang.psi.api.statements.params.ScParameter
import org.jetbrains.plugins.scala.lang.psi.implicits.NonValueFunctionTypes._
import org.jetbrains.plugins.scala.lang.psi.types.ScType
import org.jetbrains.plugins.scala.lang.psi.types.api.designator.{ScDesignatorType, ScProjectionType}
import org.jetbrains.plugins.scala.lang.psi.types.api.{TypeParameter, UndefinedType}
import org.jetbrains.plugins.scala.lang.psi.types.nonvalue.{ScMethodType, ScTypePolymorphicType}
import org.jetbrains.plugins.scala.lang.psi.types.recursiveUpdate.ScSubstitutor
import org.jetbrains.plugins.scala.macroAnnotations.Measure

import scala.collection.Set

private case class NonValueFunctionTypes(fun: ScFunction, substitutor: ScSubstitutor, typeFromMacro: Option[ScType]) {

  @volatile
  private var _undefinedData: Option[UndefinedTypeData] = _
  @volatile
  private var _methodTypeData: Option[MethodTypeData] = _

  //lazy vals may lead to deadlock, see SCL-17722
  private def lazyUndefinedData: Option[UndefinedTypeData] = {
    if (_undefinedData == null) {
      _undefinedData = computeUndefinedType(fun, substitutor, typeFromMacro)
    }
    _undefinedData
  }

  private def lazyMethodTypeData: Option[MethodTypeData] = {
    if (_methodTypeData == null) {
      _methodTypeData = lazyUndefinedData.flatMap(computeMethodType(fun, substitutor, _))
    }
    _methodTypeData
  }

  def undefinedType: Option[ScType] = lazyUndefinedData.map(_.undefinedType)

  def hadDependents: Boolean = lazyUndefinedData.exists(_.hadDependent)

  def methodType: Option[ScType] = lazyMethodTypeData.map(_.methodType)

  def hasImplicitClause: Boolean = lazyMethodTypeData.exists(_.hasImplicitClause)
}

private object NonValueFunctionTypes {

  private case class UndefinedTypeData(undefinedType: ScType, hadDependent: Boolean)

  private case class MethodTypeData(methodType: ScType, hasImplicitClause: Boolean)

  @Measure
  private def computeMethodType(fun: ScFunction,
                                substitutor: ScSubstitutor,
                                undefinedTypeData: UndefinedTypeData): Option[MethodTypeData] = {

    val typeParameters = fun.typeParameters
    val implicitClause = fun.effectiveParameterClauses.lastOption.filter(_.isImplicit)

    if (typeParameters.isEmpty && implicitClause.isEmpty) {
      None
    } else {
      val undefinedReturnType = undefinedTypeData.undefinedType

      val methodOrReturnType = implicitClause match {
        case None => undefinedReturnType
        case Some(clause) =>
{'fraction_non_alphanumeric': 0.08636193330835519, 'fraction_numerical': 0.0009366804046459348, 'mean_word_length': 4.886438809261301, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '5017235', 'n_tokens_mistral': 1618, 'n_tokens_neox': 1525, 'n_words': 269}