From 167dc81d3b62a62e503383e40adbf2492f55461b Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Tue, 12 Oct 2021 07:51:30 +0000 Subject: [PATCH] FIR/Analysis API: Get parameter name from function type notation or `@ParameterName` annotation, which is also now added during type resolution. --- .../fir/symbols/KtFirValueParameterSymbol.kt | 69 ++++++++++++-- .../fir/components/AbstractResolveCallTest.kt | 1 + .../components/ResolveCallTestGenerated.java | 36 +++++++ .../kotlin/analysis/api/calls/KtCall.kt | 3 +- .../api/symbols/KtVariableLikeSymbol.kt | 11 +++ .../variableAsFunctionWithParameterName.kt | 3 + .../variableAsFunctionWithParameterName.txt | 5 + ...leAsFunctionWithParameterNameAnnotation.kt | 3 + ...eAsFunctionWithParameterNameAnnotation.txt | 5 + ...tionWithParameterNameAnnotationConflict.kt | 4 + ...ionWithParameterNameAnnotationConflict.txt | 5 + ...iableAsFunctionWithParameterNameGeneric.kt | 6 ++ ...ableAsFunctionWithParameterNameGeneric.txt | 5 + ...ctionWithParameterNameInNonFunctionType.kt | 4 + ...tionWithParameterNameInNonFunctionType.txt | 4 + ...ariableAsFunctionWithParameterNameMixed.kt | 3 + ...riableAsFunctionWithParameterNameMixed.txt | 5 + .../extendedCheckers/unused/lambda.fir.txt | 6 +- .../kotlin/fir/resolve/ResolveUtils.kt | 51 ++++++++-- .../providers/impl/FirTypeResolverImpl.kt | 7 +- .../fir/resolve/substitution/Substitutors.kt | 8 +- .../jetbrains/kotlin/fir/FirSourceElement.kt | 5 + .../types/CustomAnnotationTypeAttribute.kt | 2 +- .../castsInsideCoroutineInference.fir.ir.txt | 94 +++++++++---------- .../castsInsideCoroutineInference.fir.kt.txt | 20 ++-- .../kotlin/builtins/StandardNames.kt | 1 + .../jetbrains/kotlin/name/StandardClassIds.kt | 2 + 27 files changed, 282 insertions(+), 86 deletions(-) create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.kt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.txt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.kt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.txt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.kt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.txt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.kt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.txt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.kt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.txt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.kt create mode 100644 analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.txt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirValueParameterSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirValueParameterSymbol.kt index fac52a78165..db1f895cbd6 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirValueParameterSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirValueParameterSymbol.kt @@ -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` 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() ?: return@withFirDeclaration defaultName + + // The parent KtDeclaration is where the variable with functional type and `@ParameterName` annotation is declared. + val parentKtDeclaration = + parameterNameAnnotation.psi?.getNonStrictParentOfType() ?: return@withFirDeclaration defaultName + val parentFirDeclaration = parentKtDeclaration.getOrBuildFirOfType(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>()?.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) { diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/AbstractResolveCallTest.kt b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/AbstractResolveCallTest.kt index c175b1bdf59..22ef8be4a8a 100644 --- a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/AbstractResolveCallTest.kt +++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/AbstractResolveCallTest.kt @@ -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() diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/ResolveCallTestGenerated.java b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/ResolveCallTestGenerated.java index 33425ae7c2e..7e580792749 100644 --- a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/ResolveCallTestGenerated.java +++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/ResolveCallTestGenerated.java @@ -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 { diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/calls/KtCall.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/calls/KtCall.kt index 31dc781a28c..1bc2830ea0e 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/calls/KtCall.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/calls/KtCall.kt @@ -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, private val _targetFunction: KtCallTarget, private val _substitutor: KtSubstitutor, override val token: ValidityToken ) : KtDeclaredFunctionCall() { + public val target: KtVariableLikeSymbol get() = withValidityAssertion { _target } override val argumentMapping: LinkedHashMap get() = withValidityAssertion { _argumentMapping } override val targetFunction: KtCallTarget diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt index bf329cddc5b..abe6e01ba05 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt @@ -138,4 +138,15 @@ public abstract class KtValueParameterSymbol : KtVariableLikeSymbol(), KtSymbolW public abstract val isVararg: Boolean abstract override fun createPointer(): KtSymbolPointer + + /** + * 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 } diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.kt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.kt new file mode 100644 index 00000000000..e65ac3da70a --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.kt @@ -0,0 +1,3 @@ +fun call(x: (a: Int, b: String) -> Unit) { + x(1, "") +} diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.txt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.txt new file mode 100644 index 00000000000..49a286f50bd --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterName.txt @@ -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(: 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 = diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.kt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.kt new file mode 100644 index 00000000000..fb3d6ede0bf --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.kt @@ -0,0 +1,3 @@ +fun call(x: Function2<@ParameterName("a") Int, @ParameterName("b") String, Unit>) { + x(1, "") +} diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.txt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.txt new file mode 100644 index 00000000000..49a286f50bd --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotation.txt @@ -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(: 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 = diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.kt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.kt new file mode 100644 index 00000000000..7f4b31dfe13 --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.kt @@ -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) { + x(1, "") +} diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.txt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.txt new file mode 100644 index 00000000000..49a286f50bd --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.txt @@ -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(: 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 = diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.kt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.kt new file mode 100644 index 00000000000..4e8c6eec180 --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.kt @@ -0,0 +1,6 @@ +fun T.foo(): (a: T) -> Unit = TODO() + +fun call() { + val x = 123.foo() + x(1) +} diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.txt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.txt new file mode 100644 index 00000000000..c698c9fe0b9 --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameGeneric.txt @@ -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(: kotlin.Function1<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int): kotlin.Unit +substitutor = diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.kt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.kt new file mode 100644 index 00000000000..336762253f8 --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.kt @@ -0,0 +1,4 @@ +// @ParameterName annotation is ignored when not used in function type +fun call(a: @ParameterName("notMe") Int, b: @ParameterName("meNeither") String) { + call(1, "") +} diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.txt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.txt new file mode 100644 index 00000000000..fd64b33b4b7 --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameInNonFunctionType.txt @@ -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 = diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.kt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.kt new file mode 100644 index 00000000000..ac776c165ef --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.kt @@ -0,0 +1,3 @@ +fun call(x: (a: Int, String) -> Unit) { + x(1, "") +} diff --git a/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.txt b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.txt new file mode 100644 index 00000000000..83e172f7f0a --- /dev/null +++ b/analysis/analysis-api/testData/analysisSession/resolveCall/variableAsFunctionWithParameterNameMixed.txt @@ -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(: 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 = diff --git a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/lambda.fir.txt b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/lambda.fir.txt index 9ccdbdcf66e..f3517513af7 100644 --- a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/lambda.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/lambda.fir.txt @@ -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|/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|/t|) } public final fun main(): R|kotlin/Unit| { - R|/f|( = f@fun (i: R|kotlin/Int|): R|kotlin/Unit| { + R|/f|( = f@fun (i: R|@R|kotlin/ParameterName|(name = String(v)) kotlin/Int|): R|kotlin/Unit| { ^@f Unit } ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index e2e320471cd..fc003f28825 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -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.toTypeProjections(): Array = 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) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt index f736b76cb07..794094cb89f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt @@ -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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt index ae53e0d4c3d..f3bf5c8dcbe 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt @@ -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 Unit` becomes `Function1<@ParameterName("x") Int, Unit>` + object ParameterNameAnnotationCall : FirFakeSourceElementKind() } sealed class FirSourceElement { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt index f7fd8b284aa..7486ab0a701 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt @@ -27,6 +27,6 @@ class CustomAnnotationTypeAttribute(val annotations: List) : Cone get() = CustomAnnotationTypeAttribute::class } -private val ConeAttributes.custom: CustomAnnotationTypeAttribute? by ConeAttributes.attributeAccessor() +val ConeAttributes.custom: CustomAnnotationTypeAttribute? by ConeAttributes.attributeAccessor() val ConeAttributes.customAnnotations: List get() = custom?.annotations.orEmpty() diff --git a/compiler/testData/ir/irText/types/castsInsideCoroutineInference.fir.ir.txt b/compiler/testData/ir/irText/types/castsInsideCoroutineInference.fir.ir.txt index 86d5bed4a44..7798f101e28 100644 --- a/compiler/testData/ir/irText/types/castsInsideCoroutineInference.fir.ir.txt +++ b/compiler/testData/ir/irText/types/castsInsideCoroutineInference.fir.ir.txt @@ -26,12 +26,12 @@ FILE fqName: fileName:/castsInsideCoroutineInference.kt $this: GET_VAR 'block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.CoroutineScope, .FlowCollector.scopedFlow>, kotlin.Unit> declared in .scopedFlow' type=@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.CoroutineScope, .FlowCollector.scopedFlow>, kotlin.Unit> origin=VARIABLE_AS_FUNCTION p1: GET_VAR ': .CoroutineScope declared in .scopedFlow..' type=.CoroutineScope origin=null p2: GET_VAR 'val collector: .FlowCollector.scopedFlow> [val] declared in .scopedFlow.' type=.FlowCollector.scopedFlow> origin=null - FUN name:onCompletion visibility:public modality:FINAL ($receiver:.Flow.onCompletion>, action:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, kotlin.Throwable?, kotlin.Unit>) returnType:.Flow.onCompletion> + FUN name:onCompletion visibility:public modality:FINAL ($receiver:.Flow.onCompletion>, action:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>) returnType:.Flow.onCompletion> TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] $receiver: VALUE_PARAMETER name: type:.Flow.onCompletion> - VALUE_PARAMETER name:action index:0 type:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, kotlin.Throwable?, kotlin.Unit> + VALUE_PARAMETER name:action index:0 type:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun onCompletion (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, kotlin.Throwable?, kotlin.Unit>): .Flow.onCompletion> declared in ' + RETURN type=kotlin.Nothing from='public final fun onCompletion (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>): .Flow.onCompletion> declared in ' CALL 'public final fun unsafeFlow (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<.FlowCollector.unsafeFlow>, kotlin.Unit>): .Flow.unsafeFlow> [inline] declared in ' type=.Flow.onCompletion> origin=null : T of .onCompletion block: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<.FlowCollector.onCompletion>, kotlin.Unit> origin=LAMBDA @@ -42,14 +42,14 @@ FILE fqName: fileName:/castsInsideCoroutineInference.kt CONSTRUCTOR_CALL 'public constructor (collector: .FlowCollector.SafeCollector>) [primary] declared in .SafeCollector' type=.SafeCollector.onCompletion> origin=null : T of .onCompletion collector: GET_VAR ': .FlowCollector.onCompletion> declared in .onCompletion.' type=.FlowCollector.onCompletion> origin=null - CALL 'public final fun invokeSafely (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.invokeSafely>, kotlin.Throwable?, kotlin.Unit>): kotlin.Unit [suspend] declared in ' type=kotlin.Unit origin=null + CALL 'public final fun invokeSafely (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.invokeSafely>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>): kotlin.Unit [suspend] declared in ' type=kotlin.Unit origin=null : T of .onCompletion $receiver: GET_VAR 'val safeCollector: .SafeCollector.onCompletion> [val] declared in .onCompletion.' type=.SafeCollector.onCompletion> origin=null - action: GET_VAR 'action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, kotlin.Throwable?, kotlin.Unit> declared in .onCompletion' type=@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, kotlin.Throwable?, kotlin.Unit> origin=null - FUN name:invokeSafely visibility:public modality:FINAL ($receiver:.FlowCollector.invokeSafely>, action:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.invokeSafely>, kotlin.Throwable?, kotlin.Unit>) returnType:kotlin.Unit [suspend] + action: GET_VAR 'action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> declared in .onCompletion' type=@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> origin=null + FUN name:invokeSafely visibility:public modality:FINAL ($receiver:.FlowCollector.invokeSafely>, action:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.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: type:.FlowCollector.invokeSafely> - VALUE_PARAMETER name:action index:0 type:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.invokeSafely>, kotlin.Throwable?, kotlin.Unit> + VALUE_PARAMETER name:action index:0 type:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.invokeSafely>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> BLOCK_BODY FUN name:unsafeFlow visibility:public modality:FINAL (block:@[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<.FlowCollector.unsafeFlow>, kotlin.Unit>) returnType:.Flow.unsafeFlow> [inline] annotations: @@ -61,25 +61,25 @@ FILE fqName: fileName:/castsInsideCoroutineInference.kt BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun unsafeFlow (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<.FlowCollector.unsafeFlow>, kotlin.Unit>): .Flow.unsafeFlow> [inline] declared in ' CALL 'public final fun TODO (): kotlin.Nothing [inline] declared in kotlin.StandardKt' type=kotlin.Nothing origin=null - FUN name:onCompletion visibility:public modality:FINAL ($receiver:.Flow.onCompletion>, action:kotlin.coroutines.SuspendFunction1) returnType:.Flow.onCompletion> + FUN name:onCompletion visibility:public modality:FINAL ($receiver:.Flow.onCompletion>, action:kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>) returnType:.Flow.onCompletion> annotations: Deprecated(message = 'binary compatibility with a version w/o FlowCollector receiver', replaceWith = , 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: type:.Flow.onCompletion> - VALUE_PARAMETER name:action index:0 type:kotlin.coroutines.SuspendFunction1 + 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 (action: kotlin.coroutines.SuspendFunction1): .Flow.onCompletion> declared in ' - CALL 'public final fun onCompletion (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, kotlin.Throwable?, kotlin.Unit>): .Flow.onCompletion> declared in ' type=.Flow.onCompletion> origin=null + RETURN type=kotlin.Nothing from='public final fun onCompletion (action: kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>): .Flow.onCompletion> declared in ' + CALL 'public final fun onCompletion (action: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit>): .Flow.onCompletion> declared in ' type=.Flow.onCompletion> origin=null : T of .onCompletion $receiver: GET_VAR ': .Flow.onCompletion> declared in .onCompletion' type=.Flow.onCompletion> origin=null - action: FUN_EXPR type=kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, kotlin.Throwable?, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.FlowCollector.onCompletion>, it:kotlin.Throwable?) returnType:kotlin.Unit [suspend] + action: FUN_EXPR type=kotlin.coroutines.SuspendFunction2<.FlowCollector.onCompletion>, @[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.FlowCollector.onCompletion>, it:@[ParameterName(name = 'cause')] kotlin.Throwable?) returnType:kotlin.Unit [suspend] $receiver: VALUE_PARAMETER name: type:.FlowCollector.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 declared in .onCompletion' type=kotlin.coroutines.SuspendFunction1 origin=VARIABLE_AS_FUNCTION - p1: GET_VAR 'it: kotlin.Throwable? declared in .onCompletion.' type=kotlin.Throwable? origin=null + $this: GET_VAR 'action: kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'cause')] kotlin.Throwable?, kotlin.Unit> declared in .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 .onCompletion.' type=@[ParameterName(name = 'cause')] kotlin.Throwable? origin=null FUN name:asFairChannel visibility:private modality:FINAL <> ($receiver:.CoroutineScope, flow:.Flow<*>) returnType:.ReceiveChannel $receiver: VALUE_PARAMETER name: type:.CoroutineScope VALUE_PARAMETER name:flow index:0 type:.Flow<*> @@ -96,63 +96,63 @@ FILE fqName: fileName:/castsInsideCoroutineInference.kt TYPE_OP type=.ChannelCoroutine origin=CAST typeOperand=.ChannelCoroutine CALL 'public abstract fun (): .SendChannel.ProducerScope> declared in .ProducerScope' type=.SendChannel origin=GET_PROPERTY $this: GET_VAR ': .ProducerScope declared in .asFairChannel.' type=.ProducerScope origin=null - CALL 'public final fun collect (action: kotlin.coroutines.SuspendFunction1.collect, kotlin.Unit>): kotlin.Unit [inline,suspend] declared in ' type=kotlin.Unit origin=null + CALL 'public final fun collect (action: kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] T of .collect, kotlin.Unit>): kotlin.Unit [inline,suspend] declared in ' type=kotlin.Unit origin=null : kotlin.Any? $receiver: GET_VAR 'flow: .Flow<*> declared in .asFairChannel' type=.Flow<*> origin=null - action: FUN_EXPR type=kotlin.coroutines.SuspendFunction1 origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: 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: 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 (value: kotlin.Any?): kotlin.Unit [suspend] declared in .asFairChannel.' + RETURN type=kotlin.Nothing from='local final fun (value: @[ParameterName(name = 'value')] kotlin.Any?): kotlin.Unit [suspend] declared in .asFairChannel.' CALL 'public final fun sendFair (element: E of .ChannelCoroutine): kotlin.Unit [suspend] declared in .ChannelCoroutine' type=kotlin.Unit origin=null $this: GET_VAR 'val channel: .ChannelCoroutine [val] declared in .asFairChannel.' type=.ChannelCoroutine 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 .asFairChannel..' 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 .asFairChannel..' 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 .asFairChannel..' type=kotlin.Any? origin=null + arg0: GET_VAR 'val tmp_0: @[ParameterName(name = 'value')] kotlin.Any? [val] declared in .asFairChannel..' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null arg1: CONST Null type=kotlin.Nothing? value=null then: CONSTRUCTOR_CALL 'public constructor () [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 .asFairChannel..' type=kotlin.Any? origin=null + then: GET_VAR 'val tmp_0: @[ParameterName(name = 'value')] kotlin.Any? [val] declared in .asFairChannel..' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null FUN name:asChannel visibility:private modality:FINAL <> ($receiver:.CoroutineScope, flow:.Flow<*>) returnType:.ReceiveChannel $receiver: VALUE_PARAMETER name: type:.CoroutineScope VALUE_PARAMETER name:flow index:0 type:.Flow<*> BLOCK_BODY RETURN type=kotlin.Nothing from='private final fun asChannel (flow: .Flow<*>): .ReceiveChannel declared in ' - CALL 'public final fun produce (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<.ProducerScope.produce>, kotlin.Unit>): .ReceiveChannel.produce> declared in ' type=.ReceiveChannel origin=null - : kotlin.Any + CALL 'public final fun produce (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<.ProducerScope.produce>, kotlin.Unit>): .ReceiveChannel.produce> declared in ' type=.ReceiveChannel<@[ParameterName(name = 'value')] kotlin.Any> origin=null + : @[ParameterName(name = 'value')] kotlin.Any $receiver: GET_VAR ': .CoroutineScope declared in .asChannel' type=.CoroutineScope origin=null - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<.ProducerScope, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.ProducerScope) returnType:kotlin.Unit [suspend] - $receiver: VALUE_PARAMETER name: type:.ProducerScope + block: FUN_EXPR type=kotlin.coroutines.SuspendFunction1<.ProducerScope<@[ParameterName(name = 'value')] kotlin.Any>, kotlin.Unit> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.ProducerScope<@[ParameterName(name = 'value')] kotlin.Any>) returnType:kotlin.Unit [suspend] + $receiver: VALUE_PARAMETER name: type:.ProducerScope<@[ParameterName(name = 'value')] kotlin.Any> BLOCK_BODY - CALL 'public final fun collect (action: kotlin.coroutines.SuspendFunction1.collect, kotlin.Unit>): kotlin.Unit [inline,suspend] declared in ' type=kotlin.Unit origin=null + CALL 'public final fun collect (action: kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] T of .collect, kotlin.Unit>): kotlin.Unit [inline,suspend] declared in ' type=kotlin.Unit origin=null : kotlin.Any? $receiver: GET_VAR 'flow: .Flow<*> declared in .asChannel' type=.Flow<*> origin=null - action: FUN_EXPR type=kotlin.coroutines.SuspendFunction1 origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: 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: 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 (value: kotlin.Any?): kotlin.Unit [suspend] declared in .asChannel.' + RETURN type=kotlin.Nothing from='local final fun (value: @[ParameterName(name = 'value')] kotlin.Any?): kotlin.Unit [suspend] declared in .asChannel.' CALL 'public abstract fun send (e: E of .SendChannel): kotlin.Unit [suspend] declared in .SendChannel' type=kotlin.Unit origin=null - $this: CALL 'public abstract fun (): .SendChannel.ProducerScope> declared in .ProducerScope' type=.SendChannel origin=GET_PROPERTY - $this: GET_VAR ': .ProducerScope declared in .asChannel.' type=.ProducerScope 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 .asChannel..' type=kotlin.Any? origin=null - WHEN type=kotlin.Any origin=ELVIS + $this: CALL 'public abstract fun (): .SendChannel.ProducerScope> declared in .ProducerScope' type=.SendChannel<@[ParameterName(name = 'value')] kotlin.Any> origin=GET_PROPERTY + $this: GET_VAR ': .ProducerScope<@[ParameterName(name = 'value')] kotlin.Any> declared in .asChannel.' type=.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 .asChannel..' 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 .asChannel..' type=kotlin.Any? origin=null + arg0: GET_VAR 'val tmp_1: @[ParameterName(name = 'value')] kotlin.Any? [val] declared in .asChannel..' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null arg1: CONST Null type=kotlin.Nothing? value=null then: CONSTRUCTOR_CALL 'public constructor () [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 .asChannel..' type=kotlin.Any? origin=null + then: GET_VAR 'val tmp_1: @[ParameterName(name = 'value')] kotlin.Any? [val] declared in .asChannel..' type=@[ParameterName(name = 'value')] kotlin.Any? origin=null CLASS CLASS name:SafeCollector modality:FINAL visibility:public superTypes:[.FlowCollector.SafeCollector>] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.SafeCollector.SafeCollector> TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] @@ -211,10 +211,10 @@ FILE fqName: fileName:/castsInsideCoroutineInference.kt BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun flowScope (block: @[ExtensionFunctionType] kotlin.coroutines.SuspendFunction1<.CoroutineScope, R of .flowScope>): R of .flowScope [suspend] declared in ' CALL 'public final fun TODO (): kotlin.Nothing [inline] declared in kotlin.StandardKt' type=kotlin.Nothing origin=null - FUN name:collect visibility:public modality:FINAL ($receiver:.Flow.collect>, action:kotlin.coroutines.SuspendFunction1.collect, kotlin.Unit>) returnType:kotlin.Unit [inline,suspend] + FUN name:collect visibility:public modality:FINAL ($receiver:.Flow.collect>, action:kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] T of .collect, kotlin.Unit>) returnType:kotlin.Unit [inline,suspend] TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] $receiver: VALUE_PARAMETER name: type:.Flow.collect> - VALUE_PARAMETER name:action index:0 type:kotlin.coroutines.SuspendFunction1.collect, kotlin.Unit> [crossinline] + VALUE_PARAMETER name:action index:0 type:kotlin.coroutines.SuspendFunction1<@[ParameterName(name = 'value')] T of .collect, kotlin.Unit> [crossinline] BLOCK_BODY CLASS CLASS name:ChannelCoroutine modality:OPEN visibility:public superTypes:[kotlin.Any] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.ChannelCoroutine.ChannelCoroutine> diff --git a/compiler/testData/ir/irText/types/castsInsideCoroutineInference.fir.kt.txt b/compiler/testData/ir/irText/types/castsInsideCoroutineInference.fir.kt.txt index 70a6f286968..b5f21f95346 100644 --- a/compiler/testData/ir/irText/types/castsInsideCoroutineInference.fir.kt.txt +++ b/compiler/testData/ir/irText/types/castsInsideCoroutineInference.fir.kt.txt @@ -10,7 +10,7 @@ fun scopedFlow(@BuilderInference block: @ExtensionFunctionType Suspen ) } -fun Flow.onCompletion(action: @ExtensionFunctionType SuspendFunction2, Throwable?, Unit>): Flow { +fun Flow.onCompletion(action: @ExtensionFunctionType SuspendFunction2, @ParameterName(name = "cause") Throwable?, Unit>): Flow { return unsafeFlow(block = local suspend fun FlowCollector.() { val safeCollector: SafeCollector = SafeCollector(collector = ) safeCollector.invokeSafely(action = action) @@ -18,7 +18,7 @@ fun Flow.onCompletion(action: @ExtensionFunctionType SuspendFuncti ) } -suspend fun FlowCollector.invokeSafely(action: @ExtensionFunctionType SuspendFunction2, Throwable?, Unit>) { +suspend fun FlowCollector.invokeSafely(action: @ExtensionFunctionType SuspendFunction2, @ParameterName(name = "cause") Throwable?, Unit>) { } @OptIn(markerClass = [ExperimentalTypeInference::class]) @@ -27,8 +27,8 @@ inline fun unsafeFlow(@BuilderInference crossinline block: @Extension } @Deprecated(message = "binary compatibility with a version w/o FlowCollector receiver", level = DeprecationLevel.HIDDEN) -fun Flow.onCompletion(action: SuspendFunction1): Flow { - return .onCompletion(action = local suspend fun FlowCollector.(it: Throwable?) { +fun Flow.onCompletion(action: SuspendFunction1<@ParameterName(name = "cause") Throwable?, Unit>): Flow { + return .onCompletion(action = local suspend fun FlowCollector.(it: @ParameterName(name = "cause") Throwable?) { action.invoke(p1 = it) } ) @@ -37,9 +37,9 @@ fun Flow.onCompletion(action: SuspendFunction1): private fun CoroutineScope.asFairChannel(flow: Flow<*>): ReceiveChannel { return .produce(block = local suspend fun ProducerScope.() { val channel: ChannelCoroutine = .() as ChannelCoroutine - flow.collect(action = local suspend fun (value: Any?) { + flow.collect(action = local suspend fun (value: @ParameterName(name = "value") Any?) { return channel.sendFair(element = { // BLOCK - val : Any? = value + val : @ParameterName(name = "value") Any? = value when { EQEQ(arg0 = , arg1 = null) -> Any() else -> @@ -52,10 +52,10 @@ private fun CoroutineScope.asFairChannel(flow: Flow<*>): ReceiveChannel { } private fun CoroutineScope.asChannel(flow: Flow<*>): ReceiveChannel { - return .produce(block = local suspend fun ProducerScope.() { - flow.collect(action = local suspend fun (value: Any?) { + return .produce<@ParameterName(name = "value") Any>(block = local suspend fun ProducerScope<@ParameterName(name = "value") Any>.() { + flow.collect(action = local suspend fun (value: @ParameterName(name = "value") Any?) { return .().send(e = { // BLOCK - val : Any? = value + val : @ParameterName(name = "value") Any? = value when { EQEQ(arg0 = , arg1 = null) -> Any() else -> @@ -93,7 +93,7 @@ suspend fun flowScope(@BuilderInference block: @ExtensionFunctionType return TODO() } -suspend inline fun Flow.collect(crossinline action: SuspendFunction1) { +suspend inline fun Flow.collect(crossinline action: SuspendFunction1<@ParameterName(name = "value") T, Unit>) { } open class ChannelCoroutine { diff --git a/core/compiler.common/src/org/jetbrains/kotlin/builtins/StandardNames.kt b/core/compiler.common/src/org/jetbrains/kotlin/builtins/StandardNames.kt index 03717df8f1e..3b1d217840a 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/builtins/StandardNames.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/builtins/StandardNames.kt @@ -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) diff --git a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt index c3c02e240c8..6c80398ce43 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt @@ -181,6 +181,8 @@ object StandardClassIds { val deprecatedSinceKotlinWarningSince = Name.identifier("warningSince") val deprecatedSinceKotlinErrorSince = Name.identifier("errorSince") val deprecatedSinceKotlinHiddenSince = Name.identifier("hiddenSince") + + val parameterNameName = jvmNameName } }