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