FIR: handle named arguments in annotations properly
This commit is contained in:
committed by
Mikhail Glukhikh
parent
4f36697737
commit
c3fc524c0d
@@ -446,9 +446,6 @@ internal fun FirReference.statementOrigin(): IrStatementOrigin? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirClass<*>.getPrimaryConstructorIfAny(): FirConstructor? =
|
|
||||||
declarations.filterIsInstance<FirConstructor>().firstOrNull()?.takeIf { it.isPrimary }
|
|
||||||
|
|
||||||
internal fun IrDeclarationParent.declareThisReceiverParameter(
|
internal fun IrDeclarationParent.declareThisReceiverParameter(
|
||||||
symbolTable: SymbolTable,
|
symbolTable: SymbolTable,
|
||||||
thisType: IrType,
|
thisType: IrType,
|
||||||
|
|||||||
+10
-6
@@ -6,10 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.backend.generators
|
package org.jetbrains.kotlin.fir.backend.generators
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.backend.*
|
import org.jetbrains.kotlin.fir.backend.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||||
import org.jetbrains.kotlin.fir.psi
|
import org.jetbrains.kotlin.fir.psi
|
||||||
@@ -19,6 +16,7 @@ import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
|||||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
import org.jetbrains.kotlin.fir.render
|
import org.jetbrains.kotlin.fir.render
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.isFunctional
|
import org.jetbrains.kotlin.fir.resolve.calls.isFunctional
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.getCorrespondingConstructorReferenceOrNull
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
|
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
@@ -327,6 +325,7 @@ class CallAndReferenceGenerator(
|
|||||||
val calleeReference = when (call) {
|
val calleeReference = when (call) {
|
||||||
is FirFunctionCall -> call.calleeReference
|
is FirFunctionCall -> call.calleeReference
|
||||||
is FirDelegatedConstructorCall -> call.calleeReference
|
is FirDelegatedConstructorCall -> call.calleeReference
|
||||||
|
is FirAnnotationCall -> call.getCorrespondingConstructorReferenceOrNull(session)
|
||||||
else -> null
|
else -> null
|
||||||
} as? FirResolvedNamedReference
|
} as? FirResolvedNamedReference
|
||||||
val function = (calleeReference?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
|
val function = (calleeReference?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
|
||||||
@@ -334,7 +333,7 @@ class CallAndReferenceGenerator(
|
|||||||
val argumentMapping = call.argumentMapping
|
val argumentMapping = call.argumentMapping
|
||||||
if (argumentMapping != null && argumentMapping.isNotEmpty()) {
|
if (argumentMapping != null && argumentMapping.isNotEmpty()) {
|
||||||
if (valueParameters != null) {
|
if (valueParameters != null) {
|
||||||
return applyArgumentsWithReorderingIfNeeded(argumentMapping, valueParameters)
|
return applyArgumentsWithReorderingIfNeeded(call, argumentMapping, valueParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ((index, argument) in call.arguments.withIndex()) {
|
for ((index, argument) in call.arguments.withIndex()) {
|
||||||
@@ -365,10 +364,15 @@ class CallAndReferenceGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun IrCallWithIndexedArgumentsBase.applyArgumentsWithReorderingIfNeeded(
|
private fun IrCallWithIndexedArgumentsBase.applyArgumentsWithReorderingIfNeeded(
|
||||||
|
call: FirCall,
|
||||||
argumentMapping: Map<FirExpression, FirValueParameter>,
|
argumentMapping: Map<FirExpression, FirValueParameter>,
|
||||||
valueParameters: List<FirValueParameter>,
|
valueParameters: List<FirValueParameter>,
|
||||||
): IrExpressionBase {
|
): IrExpressionBase {
|
||||||
if (needArgumentReordering(argumentMapping.values, valueParameters)) {
|
// Assuming compile-time constants only inside annotation, we don't need a block to reorder arguments to preserve semantics.
|
||||||
|
// But, we still need to pick correct indices for named arguments.
|
||||||
|
if (call !is FirAnnotationCall &&
|
||||||
|
needArgumentReordering(argumentMapping.values, valueParameters)
|
||||||
|
) {
|
||||||
return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply {
|
return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply {
|
||||||
for ((argument, parameter) in argumentMapping) {
|
for ((argument, parameter) in argumentMapping) {
|
||||||
val parameterIndex = valueParameters.indexOf(parameter)
|
val parameterIndex = valueParameters.indexOf(parameter)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
|||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirThisReference
|
import org.jetbrains.kotlin.fir.references.FirThisReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||||
@@ -462,3 +463,16 @@ private fun FirQualifiedAccess.expressionTypeOrUnitForAssignment(): ConeKotlinTy
|
|||||||
}
|
}
|
||||||
return StandardClassIds.Unit.constructClassLikeType(emptyArray(), isNullable = false)
|
return StandardClassIds.Unit.constructClassLikeType(emptyArray(), isNullable = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FirAnnotationCall.getCorrespondingConstructorReferenceOrNull(session: FirSession): FirResolvedNamedReference? =
|
||||||
|
annotationTypeRef.coneTypeSafe<ConeKotlinType>()?.classId?.let {
|
||||||
|
(session.firSymbolProvider.getClassLikeSymbolByFqName(it) as? FirRegularClassSymbol)?.fir
|
||||||
|
?.getPrimaryConstructorIfAny()
|
||||||
|
?.let { annotationConstructor ->
|
||||||
|
buildResolvedNamedReference {
|
||||||
|
source = this@getCorrespondingConstructorReferenceOrNull.source
|
||||||
|
name = it.shortClassName
|
||||||
|
resolvedSymbol = annotationConstructor.symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+14
-1
@@ -25,7 +25,20 @@ data class ArgumentMapping(
|
|||||||
// parameterToCallArgumentMap.values() should be [ 'bar()', 'foo()' ]
|
// parameterToCallArgumentMap.values() should be [ 'bar()', 'foo()' ]
|
||||||
val parameterToCallArgumentMap: Map<FirValueParameter, ResolvedCallArgument>,
|
val parameterToCallArgumentMap: Map<FirValueParameter, ResolvedCallArgument>,
|
||||||
val diagnostics: List<ResolutionDiagnostic>
|
val diagnostics: List<ResolutionDiagnostic>
|
||||||
)
|
) {
|
||||||
|
fun toArgumentToParameterMapping(): Map<FirExpression, FirValueParameter> {
|
||||||
|
val argumentToParameterMapping = mutableMapOf<FirExpression, FirValueParameter>()
|
||||||
|
parameterToCallArgumentMap.forEach { (valueParameter, resolvedArgument) ->
|
||||||
|
when (resolvedArgument) {
|
||||||
|
is ResolvedCallArgument.SimpleArgument -> argumentToParameterMapping[resolvedArgument.callArgument] = valueParameter
|
||||||
|
is ResolvedCallArgument.VarargArgument -> resolvedArgument.arguments.forEach {
|
||||||
|
argumentToParameterMapping[it] = valueParameter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return argumentToParameterMapping
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val EmptyArgumentMapping = ArgumentMapping(emptyMap(), emptyList())
|
private val EmptyArgumentMapping = ArgumentMapping(emptyMap(), emptyList())
|
||||||
|
|
||||||
|
|||||||
+1
-10
@@ -159,16 +159,7 @@ internal object MapArguments : ResolutionStage() {
|
|||||||
val function = symbol.fir
|
val function = symbol.fir
|
||||||
|
|
||||||
val mapping = mapArguments(callInfo.arguments, function)
|
val mapping = mapArguments(callInfo.arguments, function)
|
||||||
val argumentToParameterMapping = mutableMapOf<FirExpression, FirValueParameter>()
|
candidate.argumentMapping = mapping.toArgumentToParameterMapping()
|
||||||
mapping.parameterToCallArgumentMap.forEach { (valueParameter, resolvedArgument) ->
|
|
||||||
when (resolvedArgument) {
|
|
||||||
is ResolvedCallArgument.SimpleArgument -> argumentToParameterMapping[resolvedArgument.callArgument] = valueParameter
|
|
||||||
is ResolvedCallArgument.VarargArgument -> resolvedArgument.arguments.forEach {
|
|
||||||
argumentToParameterMapping[it] = valueParameter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
candidate.argumentMapping = argumentToParameterMapping
|
|
||||||
|
|
||||||
var applicability = CandidateApplicability.RESOLVED
|
var applicability = CandidateApplicability.RESOLVED
|
||||||
mapping.diagnostics.forEach {
|
mapping.diagnostics.forEach {
|
||||||
|
|||||||
+9
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
|||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.candidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.mapArguments
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.InvocationKindTransformer
|
import org.jetbrains.kotlin.fir.resolve.transformers.InvocationKindTransformer
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.StoreReceiver
|
import org.jetbrains.kotlin.fir.resolve.transformers.StoreReceiver
|
||||||
@@ -641,6 +642,14 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
(annotationCall.transformChildren(transformer, data) as FirAnnotationCall).also {
|
(annotationCall.transformChildren(transformer, data) as FirAnnotationCall).also {
|
||||||
// TODO: it's temporary incorrect solution until we design resolve and completion for annotation calls
|
// TODO: it's temporary incorrect solution until we design resolve and completion for annotation calls
|
||||||
it.argumentList.transformArguments(integerLiteralTypeApproximator, null)
|
it.argumentList.transformArguments(integerLiteralTypeApproximator, null)
|
||||||
|
if (it.arguments.any { arg -> arg is FirNamedArgumentExpression }) {
|
||||||
|
annotationCall.getCorrespondingConstructorReferenceOrNull(session)?.let { calleeReference ->
|
||||||
|
val argumentMapping =
|
||||||
|
mapArguments(it.arguments, calleeReference.resolvedSymbol.fir as FirFunction<*>)
|
||||||
|
.toArgumentToParameterMapping()
|
||||||
|
it.replaceArgumentList(buildResolvedArgumentList(argumentMapping))
|
||||||
|
}
|
||||||
|
}
|
||||||
it.replaceResolveStatus(status)
|
it.replaceResolveStatus(status)
|
||||||
dataFlowAnalyzer.exitAnnotationCall(it)
|
dataFlowAnalyzer.exitAnnotationCall(it)
|
||||||
}.compose()
|
}.compose()
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ val FirClassSymbol<*>.superConeTypes
|
|||||||
|
|
||||||
val FirClass<*>.superConeTypes get() = superTypeRefs.mapNotNull { it.coneTypeSafe<ConeClassLikeType>() }
|
val FirClass<*>.superConeTypes get() = superTypeRefs.mapNotNull { it.coneTypeSafe<ConeClassLikeType>() }
|
||||||
|
|
||||||
|
fun FirClass<*>.getPrimaryConstructorIfAny(): FirConstructor? =
|
||||||
|
declarations.filterIsInstance<FirConstructor>().firstOrNull()?.takeIf { it.isPrimary }
|
||||||
|
|
||||||
fun FirRegularClass.collectEnumEntries(): Collection<FirEnumEntry> {
|
fun FirRegularClass.collectEnumEntries(): Collection<FirEnumEntry> {
|
||||||
assert(classKind == ClassKind.ENUM_CLASS)
|
assert(classKind == ClassKind.ENUM_CLASS)
|
||||||
return declarations.filterIsInstance<FirEnumEntry>()
|
return declarations.filterIsInstance<FirEnumEntry>()
|
||||||
|
|||||||
Vendored
+1
-1
@@ -57,7 +57,7 @@ FILE fqName:<root> fileName:/annotationsWithDefaultParameterValues.kt
|
|||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
FUN name:test4 visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
FUN name:test4 visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
||||||
annotations:
|
annotations:
|
||||||
A(x = '456', y = <null>)
|
A(x = <null>, y = '456')
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
FUN name:test5 visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
FUN name:test5 visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
||||||
annotations:
|
annotations:
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ FILE fqName:<root> fileName:/castsInsideCoroutineInference.kt
|
|||||||
CALL 'public final fun TODO (): kotlin.Nothing [inline] declared in kotlin' type=kotlin.Nothing origin=null
|
CALL 'public final fun TODO (): kotlin.Nothing [inline] declared in kotlin' type=kotlin.Nothing origin=null
|
||||||
FUN name:onCompletion visibility:public modality:FINAL <T> ($receiver:<root>.Flow<T of <root>.onCompletion>, action:kotlin.coroutines.SuspendFunction1<kotlin.Throwable?, kotlin.Unit>) returnType:IrErrorType
|
FUN name:onCompletion visibility:public modality:FINAL <T> ($receiver:<root>.Flow<T of <root>.onCompletion>, action:kotlin.coroutines.SuspendFunction1<kotlin.Throwable?, kotlin.Unit>) returnType:IrErrorType
|
||||||
annotations:
|
annotations:
|
||||||
Deprecated(message = GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:HIDDEN' type=kotlin.DeprecationLevel, replaceWith = 'binary compatibility with a version w/o FlowCollector receiver', level = <null>)
|
Deprecated(message = 'binary compatibility with a version w/o FlowCollector receiver', replaceWith = <null>, level = GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:HIDDEN' type=kotlin.DeprecationLevel)
|
||||||
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?]
|
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?]
|
||||||
$receiver: VALUE_PARAMETER name:<this> type:<root>.Flow<T of <root>.onCompletion>
|
$receiver: VALUE_PARAMETER name:<this> type:<root>.Flow<T of <root>.onCompletion>
|
||||||
VALUE_PARAMETER name:action index:0 type:kotlin.coroutines.SuspendFunction1<kotlin.Throwable?, kotlin.Unit>
|
VALUE_PARAMETER name:action index:0 type:kotlin.coroutines.SuspendFunction1<kotlin.Throwable?, kotlin.Unit>
|
||||||
|
|||||||
Reference in New Issue
Block a user