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,
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<ConeKotlinType>()
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<ConeKotlinType>() ?: 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
)
@@ -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
@@ -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()