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
@@ -6,29 +6,42 @@
package org.jetbrains.kotlin.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.types.arrayElementType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.KtFirAnnotationCall
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.withFirDeclaration
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.getAnnotationsByClassId
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.unwrapArgument
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.types.arrayElementType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.customAnnotations
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal class KtFirValueParameterSymbol(
fir: FirValueParameter,
@@ -39,7 +52,45 @@ internal class KtFirValueParameterSymbol(
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val name: Name get() = firRef.withFir { it.name }
override val name: Name by cached {
firRef.withFir { fir ->
val defaultName = fir.name
if (fir.psi != null) return@withFir defaultName
// The case where PSI is null is when calling `invoke()` on a variable with functional type, e.g. `x(1)` below:
//
// fun foo(x: (item: Int) -> Unit) { x(1) }
// fun bar(x: Function1<@ParameterName("item") Int, Unit>) { x(1) }
//
// The function being called is `invoke(p1: Int)` on `Function1<Int, Unit>` which is from the stdlib, and therefore no source
// PSI for the function or its parameters. In that case, we use the `@ParameterName` annotation on the parameter type if present
// and fall back to the parameter names from the `invoke()` function (`p1`, `p2`, etc.).
//
// Note: During type resolution, `@ParameterName` type annotations are added based on the names (which are optional) in the
// function type notation. Therefore the `x` parameter in both example functions above have the same type and type annotations.
fir.withFirDeclaration(resolveState, FirResolvePhase.TYPES) {
val parameterNameAnnotation =
fir.returnTypeRef.coneType.attributes.customAnnotations
.getAnnotationsByClassId(StandardNames.FqNames.parameterNameClassId)
.singleOrNull()?.safeAs<FirAnnotation>() ?: return@withFirDeclaration defaultName
// The parent KtDeclaration is where the variable with functional type and `@ParameterName` annotation is declared.
val parentKtDeclaration =
parameterNameAnnotation.psi?.getNonStrictParentOfType<KtDeclaration>() ?: return@withFirDeclaration defaultName
val parentFirDeclaration = parentKtDeclaration.getOrBuildFirOfType<FirDeclaration>(resolveState)
// Resolve to ARGUMENTS_OF_ANNOTATIONS phase to get `name` argument from mapping.
val parameterNameFromAnnotation =
parentFirDeclaration.withFirDeclaration(resolveState, FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) {
val nameArgument =
parameterNameAnnotation.argumentMapping.mapping[StandardClassIds.Annotations.ParameterNames.parameterNameName]
nameArgument?.unwrapArgument()?.safeAs<FirConstExpression<*>>()?.value as? String
}
parameterNameFromAnnotation?.let { Name.identifier(it) } ?: defaultName
}
}
}
override val isVararg: Boolean get() = firRef.withFir { it.isVararg }
override val annotatedType: KtTypeAndAnnotations by firRef.withFirAndCache(FirResolvePhase.TYPES) { fir ->
if (fir.isVararg) {
@@ -91,6 +91,7 @@ private fun KtCall.stringRepresentation(): String {
append(": ${annotatedType.type.render()}")
}
is KtValueParameterSymbol -> "${if (isVararg) "vararg " else ""}$name: ${annotatedType.type.render()}"
is KtVariableSymbol -> "${if (isVal) "val" else "var"} $name: ${annotatedType.type.render()}"
is KtSuccessCallTarget -> symbol.stringValue()
is KtErrorCallTarget -> "ERR<${this.diagnostic.defaultMessage}, [${candidates.joinToString { it.stringValue() }}]>"
is Boolean -> toString()
@@ -402,6 +402,42 @@ public class ResolveCallTestGenerated extends AbstractResolveCallTest {
runTest("analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionLikeCall.kt");
}
@Test
@TestMetadata("variableAsFunctionWithParameterName.kt")
public void testVariableAsFunctionWithParameterName() throws Exception {
runTest("analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.kt");
}
@Test
@TestMetadata("variableAsFunctionWithParameterNameAnnotation.kt")
public void testVariableAsFunctionWithParameterNameAnnotation() throws Exception {
runTest("analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.kt");
}
@Test
@TestMetadata("variableAsFunctionWithParameterNameAnnotationConflict.kt")
public void testVariableAsFunctionWithParameterNameAnnotationConflict() throws Exception {
runTest("analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.kt");
}
@Test
@TestMetadata("variableAsFunctionWithParameterNameGeneric.kt")
public void testVariableAsFunctionWithParameterNameGeneric() throws Exception {
runTest("analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.kt");
}
@Test
@TestMetadata("variableAsFunctionWithParameterNameInNonFunctionType.kt")
public void testVariableAsFunctionWithParameterNameInNonFunctionType() throws Exception {
runTest("analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.kt");
}
@Test
@TestMetadata("variableAsFunctionWithParameterNameMixed.kt")
public void testVariableAsFunctionWithParameterNameMixed() throws Exception {
runTest("analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.kt");
}
@Test
@TestMetadata("variableWithExtensionInvoke.kt")
public void testVariableWithExtensionInvoke() throws Exception {
@@ -67,12 +67,13 @@ public sealed class KtDeclaredFunctionCall : KtCall() {
* fun Int.invoke() {}
*/
public class KtVariableWithInvokeFunctionCall(
public val target: KtVariableLikeSymbol,
private val _target: KtVariableLikeSymbol,
private val _argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>,
private val _targetFunction: KtCallTarget,
private val _substitutor: KtSubstitutor,
override val token: ValidityToken
) : KtDeclaredFunctionCall() {
public val target: KtVariableLikeSymbol get() = withValidityAssertion { _target }
override val argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>
get() = withValidityAssertion { _argumentMapping }
override val targetFunction: KtCallTarget
@@ -138,4 +138,15 @@ public abstract class KtValueParameterSymbol : KtVariableLikeSymbol(), KtSymbolW
public abstract val isVararg: Boolean
abstract override fun createPointer(): KtSymbolPointer<KtValueParameterSymbol>
/**
* The name of the value parameter. For a parameter of `FunctionN.invoke()` functions, the name is taken from the function type
* notation, if a name is present. For example:
* ```
* fun foo(x: (item: Int, String) -> Unit) =
* x(1, "") // or `x.invoke(1, "")`
* ```
* The names of the value parameters for `invoke()` are "item" and "p2" (its default parameter name).
*/
abstract override val name: Name
}
@@ -0,0 +1,3 @@
fun call(x: (a: Int, b: String) -> Unit) {
<expr>x(1, "")</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = x: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int), "" -> (b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String) }
targetFunction = kotlin/Function2.invoke(<dispatch receiver>: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int, b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,3 @@
fun call(x: Function2<@ParameterName("a") Int, @ParameterName("b") String, Unit>) {
<expr>x(1, "")</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = x: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int), "" -> (b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String) }
targetFunction = kotlin/Function2.invoke(<dispatch receiver>: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int, b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,4 @@
// @ParameterName annotation takes precedence over name in function type parameter
fun call(x: (notMe: @ParameterName("a") Int, meNeither: @ParameterName("b") String) -> Unit) {
<expr>x(1, "")</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = x: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int), "" -> (b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String) }
targetFunction = kotlin/Function2.invoke(<dispatch receiver>: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int, b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,6 @@
fun <T> T.foo(): (a: T) -> Unit = TODO()
fun call() {
val x = 123.foo()
<expr>x(1)</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = val x: kotlin.Function1<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int) }
targetFunction = kotlin/Function1.invoke(<dispatch receiver>: kotlin.Function1<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,4 @@
// @ParameterName annotation is ignored when not used in function type
fun call(a: @ParameterName("notMe") Int, b: @ParameterName("meNeither") String) {
<expr>call(1, "")</expr>
}
@@ -0,0 +1,4 @@
KtFunctionCall:
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(notMe)) kotlin.Int), "" -> (b: @R|kotlin.ParameterName|(name = String(meNeither)) kotlin.String) }
targetFunction = /call(a: @R|kotlin.ParameterName|(name = String(notMe)) kotlin.Int, b: @R|kotlin.ParameterName|(name = String(meNeither)) kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,3 @@
fun call(x: (a: Int, String) -> Unit) {
<expr>x(1, "")</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = x: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.String, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int), "" -> (p2: kotlin.String) }
targetFunction = kotlin/Function2.invoke(<dispatch receiver>: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.String, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int, p2: kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -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()
@@ -26,12 +26,12 @@ FILE fqName:<root> fileName:/castsInsideCoroutineInference.kt
$this: GET_VAR 'block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.CoroutineScope, <root>.FlowCollector<R of <root>.scopedFlow>, kotlin.Unit> declared in <root>.scopedFlow' type=@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.CoroutineScope, <root>.FlowCollector<R of <root>.scopedFlow>, kotlin.Unit> origin=VARIABLE_AS_FUNCTION
p1: GET_VAR '<this>: <root>.CoroutineScope declared in <root>.scopedFlow.<anonymous>.<anonymous>' type=<root>.CoroutineScope origin=null
p2: GET_VAR 'val collector: <root>.FlowCollector<R of <root>.scopedFlow> [val] declared in <root>.scopedFlow.<anonymous>' type=<root>.FlowCollector<R of <root>.scopedFlow> origin=null
FUN name:onCompletion visibility:public modality:FINAL <T> ($receiver:<root>.Flow<T of <root>.onCompletion>, action:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, kotlin.Throwable?, kotlin.Unit>) returnType:<root>.Flow<T of <root>.onCompletion>
FUN name:onCompletion visibility:public modality:FINAL <T> ($receiver:<root>.Flow<T of <root>.onCompletion>, action:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>) returnType:<root>.Flow<T of <root>.onCompletion>
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?]
$receiver: VALUE_PARAMETER name:<this> type:<root>.Flow<T of <root>.onCompletion>
VALUE_PARAMETER name:action index:0 type:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, kotlin.Throwable?, kotlin.Unit>
VALUE_PARAMETER name:action index:0 type:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun onCompletion <T> (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, kotlin.Throwable?, kotlin.Unit>): <root>.Flow<T of <root>.onCompletion> declared in <root>'
RETURN type=kotlin.Nothing from='public final fun onCompletion <T> (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>): <root>.Flow<T of <root>.onCompletion> declared in <root>'
CALL 'public final fun unsafeFlow <T> (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<<root>.FlowCollector<T of <root>.unsafeFlow>, kotlin.Unit>): <root>.Flow<T of <root>.unsafeFlow> [inline] declared in <root>' type=<root>.Flow<T of <root>.onCompletion> origin=null
<T>: T of <root>.onCompletion
block: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<<root>.FlowCollector<T of <root>.onCompletion>, kotlin.Unit> origin=LAMBDA
@@ -42,14 +42,14 @@ FILE fqName:<root> fileName:/castsInsideCoroutineInference.kt
CONSTRUCTOR_CALL 'public constructor <init> (collector: <root>.FlowCollector<T of <root>.SafeCollector>) [primary] declared in <root>.SafeCollector' type=<root>.SafeCollector<T of <root>.onCompletion> origin=null
<class: T>: T of <root>.onCompletion
collector: GET_VAR '<this>: <root>.FlowCollector<T of <root>.onCompletion> declared in <root>.onCompletion.<anonymous>' type=<root>.FlowCollector<T of <root>.onCompletion> origin=null
CALL 'public final fun invokeSafely <T> (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.invokeSafely>, kotlin.Throwable?, kotlin.Unit>): kotlin.Unit [suspend] declared in <root>' type=kotlin.Unit origin=null
CALL 'public final fun invokeSafely <T> (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.invokeSafely>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>): kotlin.Unit [suspend] declared in <root>' type=kotlin.Unit origin=null
<T>: T of <root>.onCompletion
$receiver: GET_VAR 'val safeCollector: <root>.SafeCollector<T of <root>.onCompletion> [val] declared in <root>.onCompletion.<anonymous>' type=<root>.SafeCollector<T of <root>.onCompletion> origin=null
action: GET_VAR 'action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, kotlin.Throwable?, kotlin.Unit> declared in <root>.onCompletion' type=@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, kotlin.Throwable?, kotlin.Unit> origin=null
FUN name:invokeSafely visibility:public modality:FINAL <T> ($receiver:<root>.FlowCollector<T of <root>.invokeSafely>, action:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.invokeSafely>, kotlin.Throwable?, kotlin.Unit>) returnType:kotlin.Unit [suspend]
action: GET_VAR 'action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> declared in <root>.onCompletion' type=@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> origin=null
FUN name:invokeSafely visibility:public modality:FINAL <T> ($receiver:<root>.FlowCollector<T of <root>.invokeSafely>, action:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.invokeSafely>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>) returnType:kotlin.Unit [suspend]
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?]
$receiver: VALUE_PARAMETER name:<this> type:<root>.FlowCollector<T of <root>.invokeSafely>
VALUE_PARAMETER name:action index:0 type:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.invokeSafely>, kotlin.Throwable?, kotlin.Unit>
VALUE_PARAMETER name:action index:0 type:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.invokeSafely>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>
BLOCK_BODY
FUN name:unsafeFlow visibility:public modality:FINAL <T> (block:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<<root>.FlowCollector<T of <root>.unsafeFlow>, kotlin.Unit>) returnType:<root>.Flow<T of <root>.unsafeFlow> [inline]
annotations:
@@ -61,25 +61,25 @@ FILE fqName:<root> fileName:/castsInsideCoroutineInference.kt
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun unsafeFlow <T> (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<<root>.FlowCollector<T of <root>.unsafeFlow>, kotlin.Unit>): <root>.Flow<T of <root>.unsafeFlow> [inline] declared in <root>'
CALL 'public final fun TODO (): kotlin.Nothing [inline] declared in kotlin.StandardKt' 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:<root>.Flow<T of <root>.onCompletion>
FUN name:onCompletion visibility:public modality:FINAL <T> ($receiver:<root>.Flow<T of <root>.onCompletion>, action:kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>) returnType:<root>.Flow<T of <root>.onCompletion>
annotations:
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?]
$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<@[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun onCompletion <T> (action: kotlin.coroutines.SuspendFunction1<kotlin.Throwable?, kotlin.Unit>): <root>.Flow<T of <root>.onCompletion> declared in <root>'
CALL 'public final fun onCompletion <T> (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, kotlin.Throwable?, kotlin.Unit>): <root>.Flow<T of <root>.onCompletion> declared in <root>' type=<root>.Flow<T of <root>.onCompletion> origin=null
RETURN type=kotlin.Nothing from='public final fun onCompletion <T> (action: kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>): <root>.Flow<T of <root>.onCompletion> declared in <root>'
CALL 'public final fun onCompletion <T> (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>): <root>.Flow<T of <root>.onCompletion> declared in <root>' type=<root>.Flow<T of <root>.onCompletion> origin=null
<T>: T of <root>.onCompletion
$receiver: GET_VAR '<this>: <root>.Flow<T of <root>.onCompletion> declared in <root>.onCompletion' type=<root>.Flow<T of <root>.onCompletion> origin=null
action: FUN_EXPR type=kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, kotlin.Throwable?, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:<root>.FlowCollector<T of <root>.onCompletion>, it:kotlin.Throwable?) returnType:kotlin.Unit [suspend]
action: FUN_EXPR type=kotlin.coroutines.SuspendFunction2<<root>.FlowCollector<T of <root>.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:<root>.FlowCollector<T of <root>.onCompletion>, it:@[ParameterName(name = 'cause')] kotlin.Throwable?) returnType:kotlin.Unit [suspend]
$receiver: VALUE_PARAMETER name:<this> type:<root>.FlowCollector<T of <root>.onCompletion>
VALUE_PARAMETER name:it index:0 type:kotlin.Throwable?
VALUE_PARAMETER name:it index:0 type:@[ParameterName(name = 'cause')] kotlin.Throwable?
BLOCK_BODY
CALL 'public abstract fun invoke (p1: P1 of kotlin.coroutines.SuspendFunction1): R of kotlin.coroutines.SuspendFunction1 [suspend,operator] declared in kotlin.coroutines.SuspendFunction1' type=kotlin.Unit origin=null
$this: GET_VAR 'action: kotlin.coroutines.SuspendFunction1<kotlin.Throwable?, kotlin.Unit> declared in <root>.onCompletion' type=kotlin.coroutines.SuspendFunction1<kotlin.Throwable?, kotlin.Unit> origin=VARIABLE_AS_FUNCTION
p1: GET_VAR 'it: kotlin.Throwable? declared in <root>.onCompletion.<anonymous>' type=kotlin.Throwable? origin=null
$this: GET_VAR 'action: kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> declared in <root>.onCompletion' type=kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> origin=VARIABLE_AS_FUNCTION
p1: GET_VAR 'it: @[ParameterName(name = 'cause')] kotlin.Throwable? declared in <root>.onCompletion.<anonymous>' type=@[ParameterName(name = 'cause')] kotlin.Throwable? origin=null
FUN name:asFairChannel visibility:private modality:FINAL <> ($receiver:<root>.CoroutineScope, flow:<root>.Flow<*>) returnType:<root>.ReceiveChannel<kotlin.Any>
$receiver: VALUE_PARAMETER name:<this> type:<root>.CoroutineScope
VALUE_PARAMETER name:flow index:0 type:<root>.Flow<*>
@@ -96,63 +96,63 @@ FILE fqName:<root> fileName:/castsInsideCoroutineInference.kt
TYPE_OP type=<root>.ChannelCoroutine<kotlin.Any> origin=CAST typeOperand=<root>.ChannelCoroutine<kotlin.Any>
CALL 'public abstract fun <get-channel> (): <root>.SendChannel<E of <root>.ProducerScope> declared in <root>.ProducerScope' type=<root>.SendChannel<kotlin.Nothing> origin=GET_PROPERTY
$this: GET_VAR '<this>: <root>.ProducerScope<kotlin.Any> declared in <root>.asFairChannel.<anonymous>' type=<root>.ProducerScope<kotlin.Nothing> origin=null
CALL 'public final fun collect <T> (action: kotlin.coroutines.SuspendFunction1<T of <root>.collect, kotlin.Unit>): kotlin.Unit [inline,suspend] declared in <root>' type=kotlin.Unit origin=null
CALL 'public final fun collect <T> (action: kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] T of <root>.collect, kotlin.Unit>): kotlin.Unit [inline,suspend] declared in <root>' type=kotlin.Unit origin=null
<T>: kotlin.Any?
$receiver: GET_VAR 'flow: <root>.Flow<*> declared in <root>.asFairChannel' type=<root>.Flow<*> origin=null
action: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<kotlin.Any?, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (value:kotlin.Any?) returnType:kotlin.Unit [suspend]
VALUE_PARAMETER name:value index:0 type:kotlin.Any?
action: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] kotlin.Any?, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (value:@[ParameterName(name = 'value')] kotlin.Any?) returnType:kotlin.Unit [suspend]
VALUE_PARAMETER name:value index:0 type:@[ParameterName(name = 'value')] kotlin.Any?
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (value: kotlin.Any?): kotlin.Unit [suspend] declared in <root>.asFairChannel.<anonymous>'
RETURN type=kotlin.Nothing from='local final fun <anonymous> (value: @[ParameterName(name = 'value')] kotlin.Any?): kotlin.Unit [suspend] declared in <root>.asFairChannel.<anonymous>'
CALL 'public final fun sendFair (element: E of <root>.ChannelCoroutine): kotlin.Unit [suspend] declared in <root>.ChannelCoroutine' type=kotlin.Unit origin=null
$this: GET_VAR 'val channel: <root>.ChannelCoroutine<kotlin.Any> [val] declared in <root>.asFairChannel.<anonymous>' type=<root>.ChannelCoroutine<kotlin.Any> origin=null
element: BLOCK type=kotlin.Any origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Any? [val]
GET_VAR 'value: kotlin.Any? declared in <root>.asFairChannel.<anonymous>.<anonymous>' type=kotlin.Any? origin=null
WHEN type=kotlin.Any origin=ELVIS
element: BLOCK type=@[ParameterName(name = 'value')] kotlin.Any origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:@[ParameterName(name = 'value')] kotlin.Any? [val]
GET_VAR 'value: @[ParameterName(name = 'value')] kotlin.Any? declared in <root>.asFairChannel.<anonymous>.<anonymous>' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null
WHEN type=@[ParameterName(name = 'value')] kotlin.Any origin=ELVIS
BRANCH
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: GET_VAR 'val tmp_0: kotlin.Any? [val] declared in <root>.asFairChannel.<anonymous>.<anonymous>' type=kotlin.Any? origin=null
arg0: GET_VAR 'val tmp_0: @[ParameterName(name = 'value')] kotlin.Any? [val] declared in <root>.asFairChannel.<anonymous>.<anonymous>' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null
arg1: CONST Null type=kotlin.Nothing? value=null
then: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any' type=kotlin.Any origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val tmp_0: kotlin.Any? [val] declared in <root>.asFairChannel.<anonymous>.<anonymous>' type=kotlin.Any? origin=null
then: GET_VAR 'val tmp_0: @[ParameterName(name = 'value')] kotlin.Any? [val] declared in <root>.asFairChannel.<anonymous>.<anonymous>' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null
FUN name:asChannel visibility:private modality:FINAL <> ($receiver:<root>.CoroutineScope, flow:<root>.Flow<*>) returnType:<root>.ReceiveChannel<kotlin.Any>
$receiver: VALUE_PARAMETER name:<this> type:<root>.CoroutineScope
VALUE_PARAMETER name:flow index:0 type:<root>.Flow<*>
BLOCK_BODY
RETURN type=kotlin.Nothing from='private final fun asChannel (flow: <root>.Flow<*>): <root>.ReceiveChannel<kotlin.Any> declared in <root>'
CALL 'public final fun produce <E> (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<<root>.ProducerScope<E of <root>.produce>, kotlin.Unit>): <root>.ReceiveChannel<E of <root>.produce> declared in <root>' type=<root>.ReceiveChannel<kotlin.Any> origin=null
<E>: kotlin.Any
CALL 'public final fun produce <E> (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<<root>.ProducerScope<E of <root>.produce>, kotlin.Unit>): <root>.ReceiveChannel<E of <root>.produce> declared in <root>' type=<root>.ReceiveChannel<@[ParameterName(name = 'value')] kotlin.Any> origin=null
<E>: @[ParameterName(name = 'value')] kotlin.Any
$receiver: GET_VAR '<this>: <root>.CoroutineScope declared in <root>.asChannel' type=<root>.CoroutineScope origin=null
block: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<<root>.ProducerScope<kotlin.Any>, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:<root>.ProducerScope<kotlin.Any>) returnType:kotlin.Unit [suspend]
$receiver: VALUE_PARAMETER name:<this> type:<root>.ProducerScope<kotlin.Any>
block: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<<root>.ProducerScope<@[ParameterName(name = 'value')] kotlin.Any>, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:<root>.ProducerScope<@[ParameterName(name = 'value')] kotlin.Any>) returnType:kotlin.Unit [suspend]
$receiver: VALUE_PARAMETER name:<this> type:<root>.ProducerScope<@[ParameterName(name = 'value')] kotlin.Any>
BLOCK_BODY
CALL 'public final fun collect <T> (action: kotlin.coroutines.SuspendFunction1<T of <root>.collect, kotlin.Unit>): kotlin.Unit [inline,suspend] declared in <root>' type=kotlin.Unit origin=null
CALL 'public final fun collect <T> (action: kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] T of <root>.collect, kotlin.Unit>): kotlin.Unit [inline,suspend] declared in <root>' type=kotlin.Unit origin=null
<T>: kotlin.Any?
$receiver: GET_VAR 'flow: <root>.Flow<*> declared in <root>.asChannel' type=<root>.Flow<*> origin=null
action: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<kotlin.Any?, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (value:kotlin.Any?) returnType:kotlin.Unit [suspend]
VALUE_PARAMETER name:value index:0 type:kotlin.Any?
action: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] kotlin.Any?, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (value:@[ParameterName(name = 'value')] kotlin.Any?) returnType:kotlin.Unit [suspend]
VALUE_PARAMETER name:value index:0 type:@[ParameterName(name = 'value')] kotlin.Any?
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (value: kotlin.Any?): kotlin.Unit [suspend] declared in <root>.asChannel.<anonymous>'
RETURN type=kotlin.Nothing from='local final fun <anonymous> (value: @[ParameterName(name = 'value')] kotlin.Any?): kotlin.Unit [suspend] declared in <root>.asChannel.<anonymous>'
CALL 'public abstract fun send (e: E of <root>.SendChannel): kotlin.Unit [suspend] declared in <root>.SendChannel' type=kotlin.Unit origin=null
$this: CALL 'public abstract fun <get-channel> (): <root>.SendChannel<E of <root>.ProducerScope> declared in <root>.ProducerScope' type=<root>.SendChannel<kotlin.Any> origin=GET_PROPERTY
$this: GET_VAR '<this>: <root>.ProducerScope<kotlin.Any> declared in <root>.asChannel.<anonymous>' type=<root>.ProducerScope<kotlin.Any> origin=null
e: BLOCK type=kotlin.Any origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Any? [val]
GET_VAR 'value: kotlin.Any? declared in <root>.asChannel.<anonymous>.<anonymous>' type=kotlin.Any? origin=null
WHEN type=kotlin.Any origin=ELVIS
$this: CALL 'public abstract fun <get-channel> (): <root>.SendChannel<E of <root>.ProducerScope> declared in <root>.ProducerScope' type=<root>.SendChannel<@[ParameterName(name = 'value')] kotlin.Any> origin=GET_PROPERTY
$this: GET_VAR '<this>: <root>.ProducerScope<@[ParameterName(name = 'value')] kotlin.Any> declared in <root>.asChannel.<anonymous>' type=<root>.ProducerScope<@[ParameterName(name = 'value')] kotlin.Any> origin=null
e: BLOCK type=@[ParameterName(name = 'value')] kotlin.Any origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:@[ParameterName(name = 'value')] kotlin.Any? [val]
GET_VAR 'value: @[ParameterName(name = 'value')] kotlin.Any? declared in <root>.asChannel.<anonymous>.<anonymous>' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null
WHEN type=@[ParameterName(name = 'value')] kotlin.Any origin=ELVIS
BRANCH
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: GET_VAR 'val tmp_1: kotlin.Any? [val] declared in <root>.asChannel.<anonymous>.<anonymous>' type=kotlin.Any? origin=null
arg0: GET_VAR 'val tmp_1: @[ParameterName(name = 'value')] kotlin.Any? [val] declared in <root>.asChannel.<anonymous>.<anonymous>' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null
arg1: CONST Null type=kotlin.Nothing? value=null
then: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any' type=kotlin.Any origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val tmp_1: kotlin.Any? [val] declared in <root>.asChannel.<anonymous>.<anonymous>' type=kotlin.Any? origin=null
then: GET_VAR 'val tmp_1: @[ParameterName(name = 'value')] kotlin.Any? [val] declared in <root>.asChannel.<anonymous>.<anonymous>' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null
CLASS CLASS name:SafeCollector modality:FINAL visibility:public superTypes:[<root>.FlowCollector<T of <root>.SafeCollector>]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.SafeCollector<T of <root>.SafeCollector>
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?]
@@ -211,10 +211,10 @@ FILE fqName:<root> fileName:/castsInsideCoroutineInference.kt
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun flowScope <R> (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<<root>.CoroutineScope, R of <root>.flowScope>): R of <root>.flowScope [suspend] declared in <root>'
CALL 'public final fun TODO (): kotlin.Nothing [inline] declared in kotlin.StandardKt' type=kotlin.Nothing origin=null
FUN name:collect visibility:public modality:FINAL <T> ($receiver:<root>.Flow<T of <root>.collect>, action:kotlin.coroutines.SuspendFunction1<T of <root>.collect, kotlin.Unit>) returnType:kotlin.Unit [inline,suspend]
FUN name:collect visibility:public modality:FINAL <T> ($receiver:<root>.Flow<T of <root>.collect>, action:kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] T of <root>.collect, kotlin.Unit>) returnType:kotlin.Unit [inline,suspend]
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?]
$receiver: VALUE_PARAMETER name:<this> type:<root>.Flow<T of <root>.collect>
VALUE_PARAMETER name:action index:0 type:kotlin.coroutines.SuspendFunction1<T of <root>.collect, kotlin.Unit> [crossinline]
VALUE_PARAMETER name:action index:0 type:kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] T of <root>.collect, kotlin.Unit> [crossinline]
BLOCK_BODY
CLASS CLASS name:ChannelCoroutine modality:OPEN visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.ChannelCoroutine<E of <root>.ChannelCoroutine>
@@ -10,7 +10,7 @@ fun <R : Any?> scopedFlow(@BuilderInference block: @ExtensionFunctionType Suspen
)
}
fun <T : Any?> Flow<T>.onCompletion(action: @ExtensionFunctionType SuspendFunction2<FlowCollector<T>, Throwable?, Unit>): Flow<T> {
fun <T : Any?> Flow<T>.onCompletion(action: @ExtensionFunctionType SuspendFunction2<FlowCollector<T>, @ParameterName(name = "cause") Throwable?, Unit>): Flow<T> {
return unsafeFlow<T>(block = local suspend fun FlowCollector<T>.<anonymous>() {
val safeCollector: SafeCollector<T> = SafeCollector<T>(collector = <this>)
safeCollector.invokeSafely<T>(action = action)
@@ -18,7 +18,7 @@ fun <T : Any?> Flow<T>.onCompletion(action: @ExtensionFunctionType SuspendFuncti
)
}
suspend fun <T : Any?> FlowCollector<T>.invokeSafely(action: @ExtensionFunctionType SuspendFunction2<FlowCollector<T>, Throwable?, Unit>) {
suspend fun <T : Any?> FlowCollector<T>.invokeSafely(action: @ExtensionFunctionType SuspendFunction2<FlowCollector<T>, @ParameterName(name = "cause") Throwable?, Unit>) {
}
@OptIn(markerClass = [ExperimentalTypeInference::class])
@@ -27,8 +27,8 @@ inline fun <T : Any?> unsafeFlow(@BuilderInference crossinline block: @Extension
}
@Deprecated(message = "binary compatibility with a version w/o FlowCollector receiver", level = DeprecationLevel.HIDDEN)
fun <T : Any?> Flow<T>.onCompletion(action: SuspendFunction1<Throwable?, Unit>): Flow<T> {
return <this>.onCompletion<T>(action = local suspend fun FlowCollector<T>.<anonymous>(it: Throwable?) {
fun <T : Any?> Flow<T>.onCompletion(action: SuspendFunction1<@ParameterName(name = "cause") Throwable?, Unit>): Flow<T> {
return <this>.onCompletion<T>(action = local suspend fun FlowCollector<T>.<anonymous>(it: @ParameterName(name = "cause") Throwable?) {
action.invoke(p1 = it)
}
)
@@ -37,9 +37,9 @@ fun <T : Any?> Flow<T>.onCompletion(action: SuspendFunction1<Throwable?, Unit>):
private fun CoroutineScope.asFairChannel(flow: Flow<*>): ReceiveChannel<Any> {
return <this>.produce<Any>(block = local suspend fun ProducerScope<Any>.<anonymous>() {
val channel: ChannelCoroutine<Any> = <this>.<get-channel>() as ChannelCoroutine<Any>
flow.collect<Any?>(action = local suspend fun <anonymous>(value: Any?) {
flow.collect<Any?>(action = local suspend fun <anonymous>(value: @ParameterName(name = "value") Any?) {
return channel.sendFair(element = { // BLOCK
val <elvis>: Any? = value
val <elvis>: @ParameterName(name = "value") Any? = value
when {
EQEQ(arg0 = <elvis>, arg1 = null) -> Any()
else -> <elvis>
@@ -52,10 +52,10 @@ private fun CoroutineScope.asFairChannel(flow: Flow<*>): ReceiveChannel<Any> {
}
private fun CoroutineScope.asChannel(flow: Flow<*>): ReceiveChannel<Any> {
return <this>.produce<Any>(block = local suspend fun ProducerScope<Any>.<anonymous>() {
flow.collect<Any?>(action = local suspend fun <anonymous>(value: Any?) {
return <this>.produce<@ParameterName(name = "value") Any>(block = local suspend fun ProducerScope<@ParameterName(name = "value") Any>.<anonymous>() {
flow.collect<Any?>(action = local suspend fun <anonymous>(value: @ParameterName(name = "value") Any?) {
return <this>.<get-channel>().send(e = { // BLOCK
val <elvis>: Any? = value
val <elvis>: @ParameterName(name = "value") Any? = value
when {
EQEQ(arg0 = <elvis>, arg1 = null) -> Any()
else -> <elvis>
@@ -93,7 +93,7 @@ suspend fun <R : Any?> flowScope(@BuilderInference block: @ExtensionFunctionType
return TODO()
}
suspend inline fun <T : Any?> Flow<T>.collect(crossinline action: SuspendFunction1<T, Unit>) {
suspend inline fun <T : Any?> Flow<T>.collect(crossinline action: SuspendFunction1<@ParameterName(name = "value") T, Unit>) {
}
open class ChannelCoroutine<E : Any?> {
@@ -113,6 +113,7 @@ object StandardNames {
@JvmField val replaceWith: FqName = fqName("ReplaceWith")
@JvmField val extensionFunctionType: FqName = fqName("ExtensionFunctionType")
@JvmField val parameterName: FqName = fqName("ParameterName")
@JvmField val parameterNameClassId: ClassId = ClassId.topLevel(parameterName)
@JvmField val annotation: FqName = fqName("Annotation")
@JvmField val target: FqName = annotationName("Target")
@JvmField val targetClassId: ClassId = ClassId.topLevel(target)
@@ -181,6 +181,8 @@ object StandardClassIds {
val deprecatedSinceKotlinWarningSince = Name.identifier("warningSince")
val deprecatedSinceKotlinErrorSince = Name.identifier("errorSince")
val deprecatedSinceKotlinHiddenSince = Name.identifier("hiddenSince")
val parameterNameName = jvmNameName
}
}