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:
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
+4
-3
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user