private def adaptAndApplyToImplicitArgs()

in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/psi/implicits/ImplicitCollector.scala [583:779]


  private def adaptAndApplyToImplicitArgs(
    c:                      ScalaResolveResult,
    nonValueType0:          ScType,
    hasImplicitClause:      Boolean,
    hadDependents:          Boolean,
    conformanceConstraints: ConstraintSystem,
    isLeadingImplicitsCase: Boolean
  ): Option[ScalaResolveResult] = {
    val fun            = c.element.asInstanceOf[ScFunction]
    val canContainExts = canContainTargetMethod(c)

    def wrongTypeParam(nonValueType: ScType, result: ImplicitResult): Option[ScalaResolveResult] = {
      val (valueType, typeParams) = filterTypeParamsAndInferValueType(nonValueType)

      Option(c.copy(
        problems                 = Seq(WrongTypeParameterInferred),
        implicitResultType       = Option(valueType),
        implicitReason           = result,
        unresolvedTypeParameters = Option(typeParams)
      ))
    }

    def reportParamNotFoundResult(
      resType:            ScType,
      implicitArgClauses: Seq[ImplicitArgumentsClause]
    ): Option[ScalaResolveResult] = {
      val (valueType, typeParams) = filterTypeParamsAndInferValueType(resType)

      val problems =
        for {
          clause  <- implicitArgClauses
          arg     <- clause.args
          problem <- arg.problems
        } yield problem

      val isOnlyProblemAmbiguity = problems.forall(_.is[AmbiguousImplicitParameters])

      reportWrong(
        c.copy(
          implicitArguments        = implicitArgClauses,
          implicitResultType       = Option(valueType),
          unresolvedTypeParameters = Option(typeParams)
        ),
        ImplicitParameterNotFoundResult,
        problems          = problems,
        propagateFailures = isOnlyProblemAmbiguity
      )
    }

    def noImplicitParametersResult(nonValueType: ScType): Option[ScalaResolveResult] = {
      val (valueType, typeParams) = filterTypeParamsAndInferValueType(nonValueType, !isLeadingImplicitsCase)

      val subst = conformanceConstraints.substOrEmpty

      val result = c.copy(
        subst                    = c.substitutor.followed(subst),
        implicitResultType       = Option(valueType),
        implicitReason           = OkResult,
        unresolvedTypeParameters = Option(typeParams)
      )
      Option(result)
    }

    def fullResult(
      resType:            ScType,
      implicitArgClauses: Seq[ImplicitArgumentsClause],
      constraints:        ConstraintSystem,
      checkConformance:   Boolean = false
    ): Option[ScalaResolveResult] = {
      val (valueType, typeParams) = filterTypeParamsAndInferValueType(resType, inferValueType = !isLeadingImplicitsCase)
      val allConstraints          = constraints + conformanceConstraints

      val constraintSubst = allConstraints.toSubst

      constraintSubst.fold(reportWrong(c, CantInferTypeParameterResult)) { subst =>
        val allImportsUsed =
          implicitArgClauses
            .flatMap(_.args)
            .map(_.importsUsed)
            .foldLeft(c.importsUsed)(_ ++ _)

        val result = c.copy(
          subst                    = c.substitutor.followed(subst),
          implicitResultType       = Option(valueType),
          implicitArguments        = c.implicitArguments ++ implicitArgClauses,
          implicitReason           = OkResult,
          unresolvedTypeParameters = Option(typeParams),
          importsUsed              = allImportsUsed
        )

        if (checkConformance && !valueType.conforms(tp))
          reportWrong(result, TypeDoesntConformResult, Seq(WrongTypeParameterInferred))
        else Option(result)
      }
    }

    def wrongExtensionConversion(nonValueType: ScType): Option[ScalaResolveResult] = {
      if (extensionData.isEmpty) None
      else
        filterTypeParamsAndInferValueType(nonValueType) match {
          case (FunctionType(rt, _), _) =>
            val newCandidate = c.copy(implicitResultType = Some(rt))
            if (applyExtensionPredicate(newCandidate).isEmpty)
              wrongTypeParam(nonValueType, CantFindExtensionMethodResult)
            else None
          //this is not a function, when we still need to pass implicit?..
          case _ => wrongTypeParam(nonValueType, UnhandledResult)
        }
    }

    val (nonValueType, failedPtAdapt) = {
      try {
        val updated =
          if (isLeadingImplicitsCase) nonValueType0
          else                        updateNonValueType(nonValueType0)

        val noDependents =
          if (hadDependents) UndefinedType.revertDependentTypes(updated)
          else               updated

        val propagatedError = Option.when(c.implicitReason != NoResult && c.implicitReason != OkResult){
          val (_, unresolvedTps) = filterTypeParamsAndInferValueType(nonValueType0)

          if (unresolvedTps.isEmpty) c
          else                       c.copy(unresolvedTypeParameters = Option(unresolvedTps))
        }

        (noDependents, propagatedError)
      }
      catch {
        case _: SafeCheckException =>
          val result = wrongTypeParam(nonValueType0, CantInferTypeParameterResult)

          if (canContainExts) (nonValueType0, result)
          else                return result
      }
    }

    val depth            = ScalaProjectSettings.getInstance(project).getImplicitParametersSearchDepth
    val notTooDeepSearch = depth < 0 || recursionDepth < depth

    if (hasImplicitClause && notTooDeepSearch) {
      val conversionDataCheckedResult =
        if (!hadDependents) {
          val noMethod = wrongExtensionConversion(nonValueType)
          failedPtAdapt.orElse(noMethod)
        } else failedPtAdapt

      if (!canContainExts) {
        conversionDataCheckedResult.foreach(result => return Option(result))
      }

      val throwOnAmbiguous =
        !place.isInScala3File || conversionDataCheckedResult.nonEmpty

      try {
        val (resType, implicitArgsByClause) =
          InferUtil.updateTypeWithImplicitParameters(
            nonValueType,
            place,
            Option(fun),
            canThrowSCE            = !fullInfo,
            throwOnAmbiguous       = throwOnAmbiguous,
            implicitRecursionDepth = recursionDepth + 1,
            fullInfo               = fullInfo,
            updateDeep             = !isLeadingImplicitsCase,
            isLeadingClause        = isLeadingImplicitsCase
          )

        val implicitArgs = implicitArgsByClause.flatMap(_.args)
        val constraints  = implicitArgsByClause.map(_.constraints).foldLeft(ConstraintSystem.empty)(_ + _)

        if (implicitArgs.exists(_.isImplicitParameterProblem))
          reportParamNotFoundResult(resType, implicitArgsByClause)
        else
          conversionDataCheckedResult match {
            case Some(earlierError) =>
              constraints.toSubst.fold(earlierError)(constraintSubst =>
                earlierError.copy(subst = earlierError.substitutor.followed(constraintSubst))
              ).toOption
            case _ =>
              fullResult(
                resType,
                implicitArgsByClause,
                constraints,
                checkConformance = hadDependents && !isLeadingImplicitsCase
              )
          }
      } catch {
        case _: SafeCheckException => wrongTypeParam(nonValueType, CantInferTypeParameterResult)
      }
    } else {
      failedPtAdapt.orElse(
        noImplicitParametersResult(nonValueType)
      )
    }
  }