def updateTypeWithImplicitParameters()

in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/psi/api/InferUtil.scala [67:235]


  def updateTypeWithImplicitParameters(
    tpe:                    ScType,
    place:                  PsiElement,
    coreElement:            Option[ScNamedElement],
    canThrowSCE:            Boolean,
    fullInfo:               Boolean,
    throwOnAmbiguous:       Boolean = true,
    implicitRecursionDepth: Int     = 0,
    updateDeep:             Boolean = false,
    isLeadingClause:        Boolean = false
  ): (ScType, Seq[ImplicitArgumentsClause]) = {
    implicit val elementScope: ElementScope = place.elementScope
    implicit val context: Context = Context(place)

    var implicitParameters = Option.empty[Seq[ScalaResolveResult]]
    var updatedType        = tpe
    var constraints        = ConstraintSystem.empty

    tpe.widen match {
      case t @ ScTypePolymorphicType(mt @ ScMethodType(retType, _, isImplicit), _)
        if !isImplicit && updateDeep =>
        // See SCL-3516
        val (updatedReturnType, appliedInner) =
          updateTypeWithImplicitParameters(
            t.copy(internalType = retType),
            place,
            coreElement,
            canThrowSCE,
            fullInfo = fullInfo,
            updateDeep = updateDeep
          )

        updatedType = updatedReturnType match {
          case tpt: ScTypePolymorphicType =>
            val abstractSubst      = t.abstractOrLowerTypeSubstitutor
            val mtWithoutImplicits = mt.copy(result = tpt.internalType)

            t.copy(
              internalType   = abstractSubst(mtWithoutImplicits),
              typeParameters = tpt.typeParameters
            )
          case _ => //shouldn't be there
            t.copy(
              internalType =
                mt.copy(result = updatedReturnType)
            )
        }
        return (updatedType, appliedInner)
      case ScTypePolymorphicType(internal @ ImplicitMethodOrFunctionType(retType, params), typeParams) =>
        val splitMethodType = internal match {
          case cft @ ContextFunctionType(_, _) => cft
          case mt: ScMethodType =>
            params.reverse.foldLeft(retType) {
              case (tp: ScType, param: Parameter) =>
                ScMethodType(
                  tp,
                  Seq(param),
                  hasImplicitKW = mt.hasImplicitKW,
                  hasUsingKW = mt.hasUsingKW
                )(mt.elementScope)

            }
          case other =>
            throw new IllegalStateException(
              s"Non context-function/method type returned from ImplicitMethodOrFunctionType: $other"
            )
        }

        updatedType = ScTypePolymorphicType(splitMethodType, typeParams)

        val inferredParamsBuffer = ArraySeq.newBuilder[Parameter]
        val exprsBuffer          = ArraySeq.newBuilder[Compatibility.Expression]
        val resolveResultsBuffer = ArraySeq.newBuilder[ScalaResolveResult]

        //todo: do we need to execute this loop several times?
        var i = 0
        while (i < params.size) {
          i += 1
          updatedType match {
            case t @ ScTypePolymorphicType(ImplicitMethodOrFunctionType(retTypeSingle, paramsSingle), typeParamsSingle) =>
              val abstractSubstitutor = t.abstractOrLowerTypeSubstitutor

              val (inferredParams, exprs, resolveResults) =
                findImplicits(
                  paramsSingle,
                  coreElement,
                  place,
                  canThrowSCE,
                  throwOnAmbiguous,
                  implicitRecursionDepth,
                  abstractSubstitutor
                )

              val (updatedWithLocalTypeInference, conformanceResult) =
                localTypeInferenceWithApplicabilityExt(
                  retTypeSingle,
                  inferredParams,
                  exprs,
                  typeParamsSingle,
                  canThrowSCE = canThrowSCE || fullInfo
                )

              updatedType            = updatedWithLocalTypeInference
              constraints           += conformanceResult.constraints
              inferredParamsBuffer ++= inferredParams
              exprsBuffer          ++= exprs
              resolveResultsBuffer ++= resolveResults
          }
        }

        implicitParameters = Option(resolveResultsBuffer.result())
        val dependentSubst = ScSubstitutor.paramToExprType(inferredParamsBuffer.result(), exprsBuffer.result())
        updatedType        = dependentSubst(updatedType)
      case mt @ ScMethodType(retType, _, isImplicit)
        if !isImplicit && updateDeep =>
        // See SCL-3516
        val (updatedReturnType, appliedClauses) =
          updateTypeWithImplicitParameters(
            retType,
            place,
            coreElement,
            canThrowSCE,
            fullInfo = fullInfo,
            updateDeep = updateDeep
          )

        return (mt.copy(result = updatedReturnType), appliedClauses)
      case ImplicitMethodOrFunctionType(retType, params) =>
        val (inferredParams, exprs, resolveResults) =
          findImplicits(
            params,
            coreElement,
            place,
            canThrowSCE,
            throwOnAmbiguous,
            implicitRecursionDepth
          )

        implicitParameters = Option(resolveResults)
        updatedType        = retType
        val dependentSubst = ScSubstitutor.paramToExprType(inferredParams, exprs)
        updatedType        = dependentSubst(updatedType)
      case _ =>
    }

    implicitParameters match {
      case Some(srrs) =>
        val (resultType, appliedClauses) = updateTypeWithImplicitParameters(
          updatedType,
          place,
          coreElement,
          canThrowSCE,
          throwOnAmbiguous,
          fullInfo,
          implicitRecursionDepth,
          isLeadingClause = isLeadingClause,
          updateDeep      = updateDeep
        )

        val clauseKind =
          if (isLeadingClause) ImplicitClausePosition.Leading
          else                 ImplicitClausePosition.Trailing

        val clause = ImplicitArgumentsClause(srrs, constraints, clauseKind)
        (resultType, clause +: appliedClauses)
      case None =>
        (updatedType, Seq.empty)
    }
  }