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
This commit is contained in:
committed by
TeamCityServer
parent
826ea122a9
commit
c572bf05b5
+20
-4
@@ -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<ClassId> {
|
||||
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 <T> 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)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-5
@@ -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<ConeKotlinType>,
|
||||
expectedReturnType: ConeKotlinType?,
|
||||
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
|
||||
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>,
|
||||
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")
|
||||
|
||||
+4
-2
@@ -42,7 +42,8 @@ interface LambdaAnalyzer {
|
||||
receiverType: ConeKotlinType?,
|
||||
parameters: List<ConeKotlinType>,
|
||||
expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables
|
||||
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
|
||||
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>,
|
||||
candidate: Candidate
|
||||
): ReturnArgumentsAnalysisResult
|
||||
}
|
||||
|
||||
@@ -139,7 +140,8 @@ class PostponedArgumentsAnalyzer(
|
||||
receiver,
|
||||
parameters,
|
||||
expectedTypeForReturnArguments,
|
||||
stubsForPostponedVariables
|
||||
stubsForPostponedVariables,
|
||||
candidate
|
||||
)
|
||||
applyResultsOfAnalyzedLambdaToCandidateSystem(
|
||||
c,
|
||||
|
||||
@@ -103,4 +103,23 @@ var <D : FirCallableDeclaration>
|
||||
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 <T> run(block: @Foo T.() -> Unit) {...}
|
||||
*
|
||||
* fun test() {
|
||||
* run<String> {
|
||||
* <caret>
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* The original function type `@Foo T.() -> Unit` can be accessed with this property on the FirAnonymousFunction at caret.
|
||||
*/
|
||||
var <D : FirAnonymousFunction>
|
||||
D.matchingParameterFunctionType: ConeKotlinType? by FirDeclarationDataRegistry.data(MatchingParameterFunctionTypeKey)
|
||||
|
||||
+4
-4
@@ -21,7 +21,7 @@ fun baz4(x: @MyDsl B.() -> Unit) {}
|
||||
fun @MyDsl A.baz5() {
|
||||
baz4 {
|
||||
bar()
|
||||
foo()
|
||||
<!DSL_SCOPE_VIOLATION!>foo<!>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,21 +36,21 @@ fun main() {
|
||||
baz3 {
|
||||
baz2 {
|
||||
bar()
|
||||
foo()
|
||||
<!DSL_SCOPE_VIOLATION!>foo<!>()
|
||||
}
|
||||
}
|
||||
|
||||
baz1 {
|
||||
baz4 {
|
||||
bar()
|
||||
foo()
|
||||
<!DSL_SCOPE_VIOLATION!>foo<!>()
|
||||
}
|
||||
}
|
||||
|
||||
baz3 {
|
||||
baz4 {
|
||||
bar()
|
||||
foo()
|
||||
<!DSL_SCOPE_VIOLATION!>foo<!>()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-57
@@ -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()
|
||||
<!DSL_SCOPE_VIOLATION!>foo<!>()
|
||||
}
|
||||
}
|
||||
|
||||
baz3 {
|
||||
baz2 {
|
||||
bar()
|
||||
foo()
|
||||
}
|
||||
}
|
||||
|
||||
baz1 {
|
||||
baz4 {
|
||||
bar()
|
||||
foo()
|
||||
}
|
||||
}
|
||||
|
||||
baz3 {
|
||||
baz4 {
|
||||
bar()
|
||||
foo()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// !LANGUAGE: +DslMarkerOnFunctionTypeReceiver
|
||||
|
||||
|
||||
-92
@@ -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 <T> bar1t(q: T, x: (@L1 T).() -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
foo12 {
|
||||
a()
|
||||
bar1 {
|
||||
<!DSL_SCOPE_VIOLATION!>a<!>()
|
||||
b()
|
||||
}
|
||||
|
||||
bar2 {
|
||||
<!DSL_SCOPE_VIOLATION!>a<!>()
|
||||
b()
|
||||
}
|
||||
}
|
||||
|
||||
bar1 {
|
||||
b()
|
||||
foo12 {
|
||||
a()
|
||||
<!DSL_SCOPE_VIOLATION!>b<!>()
|
||||
}
|
||||
}
|
||||
|
||||
bar2 {
|
||||
b()
|
||||
foo12 {
|
||||
a()
|
||||
<!DSL_SCOPE_VIOLATION!>b<!>()
|
||||
}
|
||||
}
|
||||
|
||||
foo2 {
|
||||
bar1t(this) {
|
||||
a()
|
||||
bar1 {
|
||||
a()
|
||||
b()
|
||||
}
|
||||
|
||||
bar2 {
|
||||
<!DSL_SCOPE_VIOLATION!>a<!>()
|
||||
b()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bar1 {
|
||||
b()
|
||||
foo2 {
|
||||
bar1t(this) {
|
||||
a()
|
||||
b()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bar2 {
|
||||
b()
|
||||
foo2 {
|
||||
bar1t(this) {
|
||||
a()
|
||||
<!DSL_SCOPE_VIOLATION!>b<!>()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
@DslMarker
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
|
||||
Vendored
-26
@@ -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 <T> foo(x: (@Ann T).() -> Unit) {}
|
||||
fun <E> bar(x: (@Ann E).() -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
foo<A> {
|
||||
a()
|
||||
bar<B> {
|
||||
a()
|
||||
this@foo.a()
|
||||
b()
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
@DslMarker
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
|
||||
Reference in New Issue
Block a user