[Analysis API] Create substitutor from type arguments defensively

- Call candidate collection sometimes provides candidate symbols to
  `createConeSubstitutorFromTypeArguments` with fewer type parameters
  than type arguments provided by `FirQualifiedAccess`, which lead to
  an NPE. Because call candidates collected for the purposes of the
  Analysis API are best-effort guesses, we can ignore the additional
  type arguments.

^KTIJ-23373 fixed
^KTIJ-21506 fixed
This commit is contained in:
Marco Pennekamp
2022-11-10 13:01:39 +01:00
parent ad6582160b
commit 60dbe73f60
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.types.TypeCheckerState
import org.jetbrains.kotlin.types.model.convertVariance import org.jetbrains.kotlin.types.model.convertVariance
@@ -99,15 +98,16 @@ internal interface KtFirAnalysisSessionComponent {
} }
fun FirQualifiedAccess.createConeSubstitutorFromTypeArguments(callableSymbol: FirCallableSymbol<*>): ConeSubstitutor { fun FirQualifiedAccess.createConeSubstitutorFromTypeArguments(callableSymbol: FirCallableSymbol<*>): ConeSubstitutor {
val typeArgumentMap = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>() val typeArgumentMap = buildMap {
for (i in typeArguments.indices) { // Type arguments are ignored defensively if `callableSymbol` can't provide enough type parameters (and vice versa). For
val type = typeArguments[i].safeAs<FirTypeProjectionWithVariance>()?.typeRef?.coneType // example, when call candidates are collected, the candidate's `callableSymbol` might have fewer type parameters than the
if (type != null) { // inferred call's type arguments.
typeArgumentMap[callableSymbol.typeParameterSymbols[i]] = type typeArguments.zip(callableSymbol.typeParameterSymbols).forEach { (typeArgument, typeParameterSymbol) ->
val type = typeArgument.safeAs<FirTypeProjectionWithVariance>()?.typeRef?.coneType ?: return@forEach
put(typeParameterSymbol, type)
} }
} }
val coneSubstitutor = substitutorByMap(typeArgumentMap, rootModuleSession) return substitutorByMap(typeArgumentMap, rootModuleSession)
return coneSubstitutor
} }
fun ConeSubstitutor.toKtSubstitutor(): KtSubstitutor { fun ConeSubstitutor.toKtSubstitutor(): KtSubstitutor {