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)
}
}