From 7d944e2023cc2e02cfd40c1291c23b023253429b Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 18 Nov 2019 17:24:28 +0300 Subject: [PATCH] FIR dispatch receiver: check nullability only (expected vs actual type) This gives a minor performance boost and prepares for upcoming K/J type mapping --- .../kotlin/fir/resolve/calls/Arguments.kt | 37 +++++++++++++++---- .../calls/PostponedArgumentsAnalyzer.kt | 7 ++-- .../kotlin/fir/resolve/calls/ResolverParts.kt | 2 + 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index 776bc23e24d..f1136fb83f7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -34,6 +34,7 @@ fun Candidate.resolveArgumentExpression( expectedTypeRef: FirTypeRef, sink: CheckerSink, isReceiver: Boolean, + isDispatch: Boolean, isSafeCall: Boolean, typeProvider: (FirExpression) -> FirTypeRef? ) { @@ -44,6 +45,7 @@ fun Candidate.resolveArgumentExpression( expectedType, sink, isReceiver, + isDispatch, isSafeCall, typeProvider ) @@ -55,6 +57,7 @@ fun Candidate.resolveArgumentExpression( expectedType, sink, isReceiver, + isDispatch, isSafeCall, typeProvider ) @@ -67,6 +70,7 @@ fun Candidate.resolveArgumentExpression( expectedType, sink, isReceiver, + isDispatch, isSafeCall, typeProvider ) @@ -81,6 +85,7 @@ fun Candidate.resolveArgumentExpression( expectedTypeRef, sink, isReceiver, + isDispatch, isSafeCall, typeProvider ) @@ -91,10 +96,11 @@ fun Candidate.resolveArgumentExpression( expectedTypeRef, sink, isReceiver, + isDispatch, isSafeCall, typeProvider ) - else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, isSafeCall, typeProvider) + else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, isDispatch, isSafeCall, typeProvider) } } @@ -105,6 +111,7 @@ private fun Candidate.resolveBlockArgument( expectedTypeRef: FirTypeRef, sink: CheckerSink, isReceiver: Boolean, + isDispatch: Boolean, isSafeCall: Boolean, typeProvider: (FirExpression) -> FirTypeRef? ) { @@ -115,9 +122,10 @@ private fun Candidate.resolveBlockArgument( block.typeRef.coneTypeUnsafe(), expectedType.type, SimpleConstraintSystemConstraintPosition, - false, - expectedType.type.withNullability(ConeNullability.NULLABLE), - sink + isReceiver = false, + isDispatch = false, + nullableExpectedType = expectedType.type.withNullability(ConeNullability.NULLABLE), + sink = sink ) return } @@ -129,6 +137,7 @@ private fun Candidate.resolveBlockArgument( expectedTypeRef, sink, isReceiver, + isDispatch, isSafeCall, typeProvider ) @@ -141,6 +150,7 @@ fun resolveSubCallArgument( expectedType: ConeKotlinType, sink: CheckerSink, isReceiver: Boolean, + isDispatch: Boolean, isSafeCall: Boolean, typeProvider: (FirExpression) -> FirTypeRef? ) { @@ -150,12 +160,13 @@ fun resolveSubCallArgument( expectedType, sink, isReceiver, + isDispatch, isSafeCall, typeProvider ) val type = sink.components.returnTypeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe()).coneTypeUnsafe() val argumentType = candidate.substitutor.substituteOrSelf(type) - resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isSafeCall) + resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, isSafeCall) } fun resolvePlainExpressionArgument( @@ -164,12 +175,13 @@ fun resolvePlainExpressionArgument( expectedType: ConeKotlinType?, sink: CheckerSink, isReceiver: Boolean, + isDispatch: Boolean, isSafeCall: Boolean, typeProvider: (FirExpression) -> FirTypeRef? ) { if (expectedType == null) return val argumentType = typeProvider(argument)?.coneTypeSafe() ?: return - resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isSafeCall) + resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, isSafeCall) } fun resolvePlainArgumentType( @@ -178,19 +190,20 @@ fun resolvePlainArgumentType( expectedType: ConeKotlinType, sink: CheckerSink, isReceiver: Boolean, + isDispatch: Boolean, isSafeCall: Boolean ) { val position = SimpleConstraintSystemConstraintPosition //TODO val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE) if (isReceiver && isSafeCall) { - if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) { + if (!isDispatch && !csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) { sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO } return } - checkApplicabilityForArgumentType(csBuilder, argumentType, expectedType, position, isReceiver, nullableExpectedType, sink) + checkApplicabilityForArgumentType(csBuilder, argumentType, expectedType, position, isReceiver, isDispatch, nullableExpectedType, sink) } private fun checkApplicabilityForArgumentType( @@ -199,9 +212,16 @@ private fun checkApplicabilityForArgumentType( expectedType: ConeKotlinType, position: SimpleConstraintSystemConstraintPosition, isReceiver: Boolean, + isDispatch: Boolean, nullableExpectedType: ConeKotlinType, sink: CheckerSink ) { + if (isReceiver && isDispatch) { + if (!expectedType.isNullable && argumentType.isMarkedNullable) { + sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) + } + return + } if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) { if (!isReceiver) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) { @@ -235,6 +255,7 @@ internal fun Candidate.resolveArgument( parameter.returnTypeRef, sink, isReceiver, + false, isSafeCall, typeProvider ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArgumentsAnalyzer.kt index 23e8267172d..7bf3e7c13d7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/PostponedArgumentsAnalyzer.kt @@ -151,9 +151,10 @@ class PostponedArgumentsAnalyzer( lambda.returnType.let(::substitute), lambda.atom.returnTypeRef, // TODO: proper ref checkerSink, - false, - false, - typeProvider + isReceiver = false, + isDispatch = false, + isSafeCall = false, + typeProvider = typeProvider ) // resolveKtPrimitive( // c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt index 6802de4ef55..3146f54b956 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt @@ -107,6 +107,7 @@ internal sealed class CheckReceivers : ResolutionStage() { expectedTypeRef = explicitReceiverExpression.typeRef, sink = sink, isReceiver = true, + isDispatch = this is Dispatch, isSafeCall = callInfo.isSafeCall, typeProvider = callInfo.typeProvider ) @@ -120,6 +121,7 @@ internal sealed class CheckReceivers : ResolutionStage() { expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type), sink = sink, isReceiver = true, + isDispatch = this is Dispatch, isSafeCall = callInfo.isSafeCall ) sink.yield()