From c572bf05b5182b6843136937bb76a41315146921 Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Wed, 15 Sep 2021 21:36:32 -0700 Subject: [PATCH] FIR checker: honor DSL marker annotation on the function type It seems the original function type gets lost during resolution. Hence thie change added a custom attribute to recover the original function type on an anonymous function --- .../fir/resolve/calls/ResolutionStages.kt | 24 ++++- .../fir/resolve/inference/FirCallCompleter.kt | 20 +++- .../inference/PostponedArgumentsAnalyzer.kt | 6 +- .../org/jetbrains/kotlin/fir/ClassMembers.kt | 19 ++++ .../dslMarker/annotatedFunctionType.fir.kt | 8 +- .../annotatedFunctionType_1_4.fir.kt | 57 ------------ .../dslMarker/annotatedFunctionType_1_4.kt | 1 + .../dslMarker/markersIntersection.fir.kt | 92 ------------------- .../resolve/dslMarker/markersIntersection.kt | 1 + .../substitutedReceiverAnnotatedType.fir.kt | 26 ------ .../substitutedReceiverAnnotatedType.kt | 1 + 11 files changed, 65 insertions(+), 190 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType_1_4.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/resolve/dslMarker/markersIntersection.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/resolve/dslMarker/substitutedReceiverAnnotatedType.fir.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index f8c7162e2d5..9bd5bfc6b5b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirVisibilityChecker import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.matchingParameterFunctionType import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.resolve.directExpansionType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType @@ -20,10 +21,7 @@ import org.jetbrains.kotlin.fir.scopes.FirUnstableSmartcastTypeScope import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol import org.jetbrains.kotlin.fir.symbols.ensureResolved -import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visibilityChecker @@ -234,6 +232,24 @@ object CheckDslScopeViolation : ResolutionStage() { @OptIn(ExperimentalStdlibApi::class) private fun ImplicitReceiverValue<*>.getDslMarkersOfImplicitReceiver(context: ResolutionContext): Set { return buildSet { + (boundSymbol as? FirAnonymousFunctionSymbol)?.fir?.matchingParameterFunctionType?.let { + // collect annotations in the function type at declaration site. For example, the `@A` and `@B` in the following code. + // ``` + // fun body(block: @A ((@B T).() -> Unit)) { ... } + // ``` + + // Collect the annotation on the function type, or `@A` in the example above. + collectDslMarkerAnnotations(context, it.attributes.customAnnotations) + + // Collect the annotation on the extension receiver, or `@B` in the example above. + if (CompilerConeAttributes.ExtensionFunctionType in it.attributes) { + it.typeArguments.firstOrNull()?.type?.let { receiverType -> + collectDslMarkerAnnotations(context, receiverType) + } + } + } + + // Collect annotations on the actual receiver type. collectDslMarkerAnnotations(context, type) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt index eab0d15a7c5..fb94f208954 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt @@ -10,10 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter -import org.jetbrains.kotlin.fir.expressions.FirExpression -import org.jetbrains.kotlin.fir.expressions.FirResolvable -import org.jetbrains.kotlin.fir.expressions.FirStatement -import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment +import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.expectedType @@ -236,11 +233,24 @@ class FirCallCompleter( receiverType: ConeKotlinType?, parameters: List, expectedReturnType: ConeKotlinType?, - stubsForPostponedVariables: Map + stubsForPostponedVariables: Map, + candidate: Candidate ): ReturnArgumentsAnalysisResult { val lambdaArgument: FirAnonymousFunction = lambdaAtom.atom val needItParam = lambdaArgument.valueParameters.isEmpty() && parameters.size == 1 + val matchedParameter = candidate.argumentMapping?.firstNotNullOfOrNull { (currentArgument, currentValueParameter) -> + val currentLambdaArgument = + ((currentArgument as? FirLambdaArgumentExpression)?.expression as? FirAnonymousFunctionExpression)?.anonymousFunction + if (currentLambdaArgument === lambdaArgument) { + currentValueParameter + } else { + null + } + } + + lambdaArgument.matchingParameterFunctionType = matchedParameter?.returnTypeRef?.coneType + val itParam = when { needItParam -> { val name = Name.identifier("it") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt index b52e2e34b8f..e0f1d86aed9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt @@ -42,7 +42,8 @@ interface LambdaAnalyzer { receiverType: ConeKotlinType?, parameters: List, expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables - stubsForPostponedVariables: Map + stubsForPostponedVariables: Map, + candidate: Candidate ): ReturnArgumentsAnalysisResult } @@ -139,7 +140,8 @@ class PostponedArgumentsAnalyzer( receiver, parameters, expectedTypeForReturnArguments, - stubsForPostponedVariables + stubsForPostponedVariables, + candidate ) applyResultsOfAnalyzedLambdaToCandidateSystem( c, diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt index 734f826aa04..8bcc1542f43 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt @@ -103,4 +103,23 @@ var D.originalForIntersectionOverrideAttr: D? by FirDeclarationDataRegistry.data(IntersectionOverrideOriginalKey) private object InitialSignatureKey : FirDeclarationDataKey() + var FirCallableDeclaration.initialSignatureAttr: FirCallableDeclaration? by FirDeclarationDataRegistry.data(InitialSignatureKey) + +private object MatchingParameterFunctionTypeKey : FirDeclarationDataKey() + +/** + * Consider the following + * ``` + * fun run(block: @Foo T.() -> Unit) {...} + * + * fun test() { + * run { + * + * } + * } + * ``` + * The original function type `@Foo T.() -> Unit` can be accessed with this property on the FirAnonymousFunction at caret. + */ +var + D.matchingParameterFunctionType: ConeKotlinType? by FirDeclarationDataRegistry.data(MatchingParameterFunctionTypeKey) diff --git a/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType.fir.kt b/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType.fir.kt index cd70b96e197..4cdb3ba7f72 100644 --- a/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType.fir.kt @@ -21,7 +21,7 @@ fun baz4(x: @MyDsl B.() -> Unit) {} fun @MyDsl A.baz5() { baz4 { bar() - foo() + foo() } } @@ -36,21 +36,21 @@ fun main() { baz3 { baz2 { bar() - foo() + foo() } } baz1 { baz4 { bar() - foo() + foo() } } baz3 { baz4 { bar() - foo() + foo() } } diff --git a/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType_1_4.fir.kt b/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType_1_4.fir.kt deleted file mode 100644 index 3b1fd1ccbc2..00000000000 --- a/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType_1_4.fir.kt +++ /dev/null @@ -1,57 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER -// !LANGUAGE: +DslMarkerOnFunctionTypeReceiver - -@Target(AnnotationTarget.TYPE) -@DslMarker -annotation class MyDsl - -interface A { - fun foo() -} - -interface B { - fun bar() -} - -fun baz1(x: (@MyDsl A).() -> Unit) {} -fun baz2(x: (@MyDsl B).() -> Unit) {} -fun baz3(x: @MyDsl A.() -> Unit) {} -fun baz4(x: @MyDsl B.() -> Unit) {} - -fun @MyDsl A.baz5() { - baz4 { - bar() - foo() - } -} - -fun main() { - baz1 { - baz2 { - bar() - foo() - } - } - - baz3 { - baz2 { - bar() - foo() - } - } - - baz1 { - baz4 { - bar() - foo() - } - } - - baz3 { - baz4 { - bar() - foo() - } - } - -} diff --git a/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType_1_4.kt b/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType_1_4.kt index da1020399d7..4434685fa7f 100644 --- a/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType_1_4.kt +++ b/compiler/testData/diagnostics/tests/resolve/dslMarker/annotatedFunctionType_1_4.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER // !LANGUAGE: +DslMarkerOnFunctionTypeReceiver diff --git a/compiler/testData/diagnostics/tests/resolve/dslMarker/markersIntersection.fir.kt b/compiler/testData/diagnostics/tests/resolve/dslMarker/markersIntersection.fir.kt deleted file mode 100644 index 89f88f4c9d2..00000000000 --- a/compiler/testData/diagnostics/tests/resolve/dslMarker/markersIntersection.fir.kt +++ /dev/null @@ -1,92 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER -@DslMarker -@Target(AnnotationTarget.TYPE) -annotation class L1 - -@DslMarker -@Target(AnnotationTarget.TYPE) -annotation class L2 - -class A { - fun a() = 1 -} - -class B { - fun b() = 2 -} - -fun foo1(x: (@L1 A).() -> Unit) {} -fun foo2(x: (@L2 A).() -> Unit) {} - -fun foo12(x: (@L1 @L2 A).() -> Unit) {} - -fun bar1(x: (@L1 B).() -> Unit) {} -fun bar2(x: (@L2 B).() -> Unit) {} - -fun bar1t(q: T, x: (@L1 T).() -> Unit) {} - -fun test() { - foo12 { - a() - bar1 { - a() - b() - } - - bar2 { - a() - b() - } - } - - bar1 { - b() - foo12 { - a() - b() - } - } - - bar2 { - b() - foo12 { - a() - b() - } - } - - foo2 { - bar1t(this) { - a() - bar1 { - a() - b() - } - - bar2 { - a() - b() - } - } - } - - bar1 { - b() - foo2 { - bar1t(this) { - a() - b() - } - } - } - - bar2 { - b() - foo2 { - bar1t(this) { - a() - b() - } - } - } -} diff --git a/compiler/testData/diagnostics/tests/resolve/dslMarker/markersIntersection.kt b/compiler/testData/diagnostics/tests/resolve/dslMarker/markersIntersection.kt index 4e5850e0a7c..ffd50f94f24 100644 --- a/compiler/testData/diagnostics/tests/resolve/dslMarker/markersIntersection.kt +++ b/compiler/testData/diagnostics/tests/resolve/dslMarker/markersIntersection.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER @DslMarker @Target(AnnotationTarget.TYPE) diff --git a/compiler/testData/diagnostics/tests/resolve/dslMarker/substitutedReceiverAnnotatedType.fir.kt b/compiler/testData/diagnostics/tests/resolve/dslMarker/substitutedReceiverAnnotatedType.fir.kt deleted file mode 100644 index 71215b5040b..00000000000 --- a/compiler/testData/diagnostics/tests/resolve/dslMarker/substitutedReceiverAnnotatedType.fir.kt +++ /dev/null @@ -1,26 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER -@DslMarker -@Target(AnnotationTarget.TYPE) -annotation class Ann - -class A { - fun a() = 1 -} - -class B { - fun b() = 2 -} - -fun foo(x: (@Ann T).() -> Unit) {} -fun bar(x: (@Ann E).() -> Unit) {} - -fun test() { - foo { - a() - bar { - a() - this@foo.a() - b() - } - } -} diff --git a/compiler/testData/diagnostics/tests/resolve/dslMarker/substitutedReceiverAnnotatedType.kt b/compiler/testData/diagnostics/tests/resolve/dslMarker/substitutedReceiverAnnotatedType.kt index bdd29eee30e..fc591068f6c 100644 --- a/compiler/testData/diagnostics/tests/resolve/dslMarker/substitutedReceiverAnnotatedType.kt +++ b/compiler/testData/diagnostics/tests/resolve/dslMarker/substitutedReceiverAnnotatedType.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER @DslMarker @Target(AnnotationTarget.TYPE)