FIR dispatch receiver: check nullability only (expected vs actual type)

This gives a minor performance boost and prepares for upcoming K/J type mapping
This commit is contained in:
Mikhail Glukhikh
2019-11-18 17:24:28 +03:00
parent 0dc7c37b62
commit 7d944e2023
3 changed files with 35 additions and 11 deletions
@@ -34,6 +34,7 @@ fun Candidate.resolveArgumentExpression(
expectedTypeRef: FirTypeRef, expectedTypeRef: FirTypeRef,
sink: CheckerSink, sink: CheckerSink,
isReceiver: Boolean, isReceiver: Boolean,
isDispatch: Boolean,
isSafeCall: Boolean, isSafeCall: Boolean,
typeProvider: (FirExpression) -> FirTypeRef? typeProvider: (FirExpression) -> FirTypeRef?
) { ) {
@@ -44,6 +45,7 @@ fun Candidate.resolveArgumentExpression(
expectedType, expectedType,
sink, sink,
isReceiver, isReceiver,
isDispatch,
isSafeCall, isSafeCall,
typeProvider typeProvider
) )
@@ -55,6 +57,7 @@ fun Candidate.resolveArgumentExpression(
expectedType, expectedType,
sink, sink,
isReceiver, isReceiver,
isDispatch,
isSafeCall, isSafeCall,
typeProvider typeProvider
) )
@@ -67,6 +70,7 @@ fun Candidate.resolveArgumentExpression(
expectedType, expectedType,
sink, sink,
isReceiver, isReceiver,
isDispatch,
isSafeCall, isSafeCall,
typeProvider typeProvider
) )
@@ -81,6 +85,7 @@ fun Candidate.resolveArgumentExpression(
expectedTypeRef, expectedTypeRef,
sink, sink,
isReceiver, isReceiver,
isDispatch,
isSafeCall, isSafeCall,
typeProvider typeProvider
) )
@@ -91,10 +96,11 @@ fun Candidate.resolveArgumentExpression(
expectedTypeRef, expectedTypeRef,
sink, sink,
isReceiver, isReceiver,
isDispatch,
isSafeCall, isSafeCall,
typeProvider 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, expectedTypeRef: FirTypeRef,
sink: CheckerSink, sink: CheckerSink,
isReceiver: Boolean, isReceiver: Boolean,
isDispatch: Boolean,
isSafeCall: Boolean, isSafeCall: Boolean,
typeProvider: (FirExpression) -> FirTypeRef? typeProvider: (FirExpression) -> FirTypeRef?
) { ) {
@@ -115,9 +122,10 @@ private fun Candidate.resolveBlockArgument(
block.typeRef.coneTypeUnsafe(), block.typeRef.coneTypeUnsafe(),
expectedType.type, expectedType.type,
SimpleConstraintSystemConstraintPosition, SimpleConstraintSystemConstraintPosition,
false, isReceiver = false,
expectedType.type.withNullability(ConeNullability.NULLABLE), isDispatch = false,
sink nullableExpectedType = expectedType.type.withNullability(ConeNullability.NULLABLE),
sink = sink
) )
return return
} }
@@ -129,6 +137,7 @@ private fun Candidate.resolveBlockArgument(
expectedTypeRef, expectedTypeRef,
sink, sink,
isReceiver, isReceiver,
isDispatch,
isSafeCall, isSafeCall,
typeProvider typeProvider
) )
@@ -141,6 +150,7 @@ fun resolveSubCallArgument(
expectedType: ConeKotlinType, expectedType: ConeKotlinType,
sink: CheckerSink, sink: CheckerSink,
isReceiver: Boolean, isReceiver: Boolean,
isDispatch: Boolean,
isSafeCall: Boolean, isSafeCall: Boolean,
typeProvider: (FirExpression) -> FirTypeRef? typeProvider: (FirExpression) -> FirTypeRef?
) { ) {
@@ -150,12 +160,13 @@ fun resolveSubCallArgument(
expectedType, expectedType,
sink, sink,
isReceiver, isReceiver,
isDispatch,
isSafeCall, isSafeCall,
typeProvider typeProvider
) )
val type = sink.components.returnTypeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe()).coneTypeUnsafe<ConeKotlinType>() val type = sink.components.returnTypeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe()).coneTypeUnsafe<ConeKotlinType>()
val argumentType = candidate.substitutor.substituteOrSelf(type) val argumentType = candidate.substitutor.substituteOrSelf(type)
resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isSafeCall) resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, isSafeCall)
} }
fun resolvePlainExpressionArgument( fun resolvePlainExpressionArgument(
@@ -164,12 +175,13 @@ fun resolvePlainExpressionArgument(
expectedType: ConeKotlinType?, expectedType: ConeKotlinType?,
sink: CheckerSink, sink: CheckerSink,
isReceiver: Boolean, isReceiver: Boolean,
isDispatch: Boolean,
isSafeCall: Boolean, isSafeCall: Boolean,
typeProvider: (FirExpression) -> FirTypeRef? typeProvider: (FirExpression) -> FirTypeRef?
) { ) {
if (expectedType == null) return if (expectedType == null) return
val argumentType = typeProvider(argument)?.coneTypeSafe<ConeKotlinType>() ?: return val argumentType = typeProvider(argument)?.coneTypeSafe<ConeKotlinType>() ?: return
resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isSafeCall) resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, isSafeCall)
} }
fun resolvePlainArgumentType( fun resolvePlainArgumentType(
@@ -178,19 +190,20 @@ fun resolvePlainArgumentType(
expectedType: ConeKotlinType, expectedType: ConeKotlinType,
sink: CheckerSink, sink: CheckerSink,
isReceiver: Boolean, isReceiver: Boolean,
isDispatch: Boolean,
isSafeCall: Boolean isSafeCall: Boolean
) { ) {
val position = SimpleConstraintSystemConstraintPosition //TODO val position = SimpleConstraintSystemConstraintPosition //TODO
val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE) val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE)
if (isReceiver && isSafeCall) { if (isReceiver && isSafeCall) {
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) { if (!isDispatch && !csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) {
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO
} }
return return
} }
checkApplicabilityForArgumentType(csBuilder, argumentType, expectedType, position, isReceiver, nullableExpectedType, sink) checkApplicabilityForArgumentType(csBuilder, argumentType, expectedType, position, isReceiver, isDispatch, nullableExpectedType, sink)
} }
private fun checkApplicabilityForArgumentType( private fun checkApplicabilityForArgumentType(
@@ -199,9 +212,16 @@ private fun checkApplicabilityForArgumentType(
expectedType: ConeKotlinType, expectedType: ConeKotlinType,
position: SimpleConstraintSystemConstraintPosition, position: SimpleConstraintSystemConstraintPosition,
isReceiver: Boolean, isReceiver: Boolean,
isDispatch: Boolean,
nullableExpectedType: ConeKotlinType, nullableExpectedType: ConeKotlinType,
sink: CheckerSink sink: CheckerSink
) { ) {
if (isReceiver && isDispatch) {
if (!expectedType.isNullable && argumentType.isMarkedNullable) {
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER)
}
return
}
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
if (!isReceiver) { if (!isReceiver) {
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) {
@@ -235,6 +255,7 @@ internal fun Candidate.resolveArgument(
parameter.returnTypeRef, parameter.returnTypeRef,
sink, sink,
isReceiver, isReceiver,
false,
isSafeCall, isSafeCall,
typeProvider typeProvider
) )
@@ -151,9 +151,10 @@ class PostponedArgumentsAnalyzer(
lambda.returnType.let(::substitute), lambda.returnType.let(::substitute),
lambda.atom.returnTypeRef, // TODO: proper ref lambda.atom.returnTypeRef, // TODO: proper ref
checkerSink, checkerSink,
false, isReceiver = false,
false, isDispatch = false,
typeProvider isSafeCall = false,
typeProvider = typeProvider
) )
// resolveKtPrimitive( // resolveKtPrimitive(
// c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false // c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false
@@ -107,6 +107,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
expectedTypeRef = explicitReceiverExpression.typeRef, expectedTypeRef = explicitReceiverExpression.typeRef,
sink = sink, sink = sink,
isReceiver = true, isReceiver = true,
isDispatch = this is Dispatch,
isSafeCall = callInfo.isSafeCall, isSafeCall = callInfo.isSafeCall,
typeProvider = callInfo.typeProvider typeProvider = callInfo.typeProvider
) )
@@ -120,6 +121,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type), expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type),
sink = sink, sink = sink,
isReceiver = true, isReceiver = true,
isDispatch = this is Dispatch,
isSafeCall = callInfo.isSafeCall isSafeCall = callInfo.isSafeCall
) )
sink.yield() sink.yield()