FIR/Analysis API: Get parameter name from function type notation or

`@ParameterName` annotation, which is also now added during type
resolution.
This commit is contained in:
Mark Punzalan
2021-10-12 07:51:30 +00:00
committed by Dmitriy Novozhilov
parent afb68d15d6
commit 167dc81d3b
27 changed files with 282 additions and 86 deletions
@@ -1,9 +1,9 @@
FILE: lambda.kt
public final fun f(t: R|(kotlin/Int) -> kotlin/Unit|): R|kotlin/Unit| {
Int(1).R|kotlin/run|<R|kotlin/Int|, R|kotlin/Unit|>(R|<local>/t|)
public final fun f(t: R|(@R|kotlin/ParameterName|(name = String(v)) kotlin/Int) -> kotlin/Unit|): R|kotlin/Unit| {
Int(1).R|kotlin/run|<R|@R|kotlin/ParameterName|(name = String(v)) kotlin/Int|, R|kotlin/Unit|>(R|<local>/t|)
}
public final fun main(): R|kotlin/Unit| {
R|/f|(<L> = f@fun <anonymous>(i: R|kotlin/Int|): R|kotlin/Unit| <inline=NoInline> {
R|/f|(<L> = f@fun <anonymous>(i: R|@R|kotlin/ParameterName|(name = String(v)) kotlin/Int|): R|kotlin/Unit| <inline=NoInline> {
^@f Unit
}
)
@@ -5,16 +5,13 @@
package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.canNarrowDownGetterType
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
@@ -47,12 +44,49 @@ import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.types.SmartcastStability
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun List<FirQualifierPart>.toTypeProjections(): Array<ConeTypeProjection> =
asReversed().flatMap { it.typeArgumentList.typeArguments.map { typeArgument -> typeArgument.toConeTypeProjection() } }.toTypedArray()
fun ConeKotlinType.withParameterNameAnnotation(valueParameter: FirValueParameter, context: ConeTypeContext): ConeKotlinType {
if (valueParameter.name == SpecialNames.NO_NAME_PROVIDED || valueParameter.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR) return this
// Existing @ParameterName annotation takes precedence
if (attributes.customAnnotations.getAnnotationsByClassId(StandardNames.FqNames.parameterNameClassId).isNotEmpty()) return this
val fakeSource = valueParameter.source?.fakeElement(FirFakeSourceElementKind.ParameterNameAnnotationCall)
val parameterNameAnnotationCall = buildAnnotation {
source = fakeSource
annotationTypeRef =
buildResolvedTypeRef {
source = fakeSource
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(StandardNames.FqNames.parameterNameClassId),
emptyArray(),
isNullable = false
)
}
argumentMapping = buildAnnotationArgumentMapping {
mapping[StandardClassIds.Annotations.ParameterNames.parameterNameName] =
buildConstExpression(fakeSource, ConstantValueKind.String, valueParameter.name.asString(), setType = true)
}
}
val attributesWithParameterNameAnnotation =
ConeAttributes.create(listOf(CustomAnnotationTypeAttribute(listOf(parameterNameAnnotationCall))))
return withCombinedCustomAttributesFrom(attributesWithParameterNameAnnotation, context)
}
fun ConeKotlinType.withCombinedCustomAttributesFrom(other: ConeKotlinType, context: ConeTypeContext): ConeKotlinType =
withCombinedCustomAttributesFrom(other.attributes, context)
private fun ConeKotlinType.withCombinedCustomAttributesFrom(other: ConeAttributes, context: ConeTypeContext): ConeKotlinType {
val customAttributesFromOther = other.custom ?: return this
val combinedConeAttributes = attributes.add(ConeAttributes.create(listOf(customAttributesFromOther)))
return withAttributes(combinedConeAttributes, context)
}
fun FirFunction.constructFunctionalType(isSuspend: Boolean = false): ConeLookupTagBasedType {
val receiverTypeRef = when (this) {
is FirSimpleFunction -> receiverTypeRef
@@ -446,9 +480,10 @@ private fun initialTypeOfCandidate(candidate: Candidate, typeRef: FirResolvedTyp
return candidate.substitutor.substituteOrSelf(typeRef.type)
}
fun FirCallableDeclaration.getContainingClass(session: FirSession): FirRegularClass? = this.containingClass()?.let { lookupTag ->
session.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirRegularClass
}
fun FirCallableDeclaration.getContainingClass(session: FirSession): FirRegularClass? =
this.containingClass()?.let { lookupTag ->
session.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirRegularClass
}
fun FirFunction.getAsForbiddenNamedArgumentsTarget(session: FirSession): ForbiddenNamedArgumentsTarget? {
if (this is FirConstructor && this.isPrimary) {
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.providers.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
@@ -16,7 +14,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeUnexpectedTypeArgumentsError
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeOuterClassArgumentsRequired
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedQualifierError
@@ -348,7 +345,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
private fun createFunctionalType(typeRef: FirFunctionTypeRef): ConeClassLikeType {
val parameters =
listOfNotNull(typeRef.receiverTypeRef?.coneType) +
typeRef.valueParameters.map { it.returnTypeRef.coneType } +
typeRef.valueParameters.map { it.returnTypeRef.coneType.withParameterNameAnnotation(it, session.typeContext) } +
listOf(typeRef.returnTypeRef.coneType)
val classId = if (typeRef.isSuspend) {
StandardClassIds.SuspendFunctionN(typeRef.parametersCount)
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.substitution
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
import org.jetbrains.kotlin.fir.resolve.withCombinedCustomAttributesFrom
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
@@ -164,7 +165,10 @@ data class ConeSubstitutorByMap(
) : AbstractConeSubstitutor(useSiteSession.typeContext) {
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
if (type !is ConeTypeParameterType) return null
val result = substitution[type.lookupTag.symbol].updateNullabilityIfNeeded(type) ?: return null
val result =
substitution[type.lookupTag.symbol].updateNullabilityIfNeeded(type)
?.withCombinedCustomAttributesFrom(type, useSiteSession.typeContext)
?: return null
if (type.isUnsafeVarianceType(useSiteSession)) {
return useSiteSession.inferenceComponents.approximator.approximateToSuperType(
result, TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
@@ -180,7 +184,7 @@ fun createTypeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, ConeK
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
if (type !is ConeLookupTagBasedType && type !is ConeStubType) return null
val new = map[type.typeConstructor(context)] ?: return null
return new.approximateIntegerLiteralType().updateNullabilityIfNeeded(type)
return new.approximateIntegerLiteralType().updateNullabilityIfNeeded(type)?.withCombinedCustomAttributesFrom(type, context)
}
}
}
@@ -183,6 +183,11 @@ sealed class FirFakeSourceElementKind : FirSourceElementKind() {
// for annotation moved to another element due to annotation use-site target
object FromUseSiteTarget : FirFakeSourceElementKind()
// for `@ParameterName` annotation call added to function types with names in the notation
// with a fake source that refers to the value parameter in the function type notation
// e.g., `(x: Int) -> Unit` becomes `Function1<@ParameterName("x") Int, Unit>`
object ParameterNameAnnotationCall : FirFakeSourceElementKind()
}
sealed class FirSourceElement {
@@ -27,6 +27,6 @@ class CustomAnnotationTypeAttribute(val annotations: List<FirAnnotation>) : Cone
get() = CustomAnnotationTypeAttribute::class
}
private val ConeAttributes.custom: CustomAnnotationTypeAttribute? by ConeAttributes.attributeAccessor<CustomAnnotationTypeAttribute>()
val ConeAttributes.custom: CustomAnnotationTypeAttribute? by ConeAttributes.attributeAccessor<CustomAnnotationTypeAttribute>()
val ConeAttributes.customAnnotations: List<FirAnnotation> get() = custom?.annotations.orEmpty()