[FE 1.0] Don't fail on calls of functions with contracts from object

^KT-51704 Fixed
This commit is contained in:
Dmitriy Novozhilov
2022-05-12 14:03:58 +03:00
committed by teamcity
parent 993021a71d
commit 4d5a4ccd6b
7 changed files with 129 additions and 7 deletions
@@ -35747,6 +35747,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/externalArguments.kt");
}
@Test
@TestMetadata("functionInCompanion.kt")
public void testFunctionInCompanion() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/functionInCompanion.kt");
}
@Test
@TestMetadata("intersectingInfo.kt")
public void testIntersectingInfo() throws Exception {
@@ -35747,6 +35747,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/externalArguments.kt");
}
@Test
@TestMetadata("functionInCompanion.kt")
public void testFunctionInCompanion() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/functionInCompanion.kt");
}
@Test
@TestMetadata("intersectingInfo.kt")
public void testIntersectingInfo() throws Exception {
@@ -35747,6 +35747,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/externalArguments.kt");
}
@Test
@TestMetadata("functionInCompanion.kt")
public void testFunctionInCompanion() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/functionInCompanion.kt");
}
@Test
@TestMetadata("intersectingInfo.kt")
public void testIntersectingInfo() throws Exception {
@@ -20,8 +20,11 @@ import org.jetbrains.kotlin.contracts.model.*
import org.jetbrains.kotlin.contracts.model.structure.*
import org.jetbrains.kotlin.contracts.model.visitors.Reducer
import org.jetbrains.kotlin.contracts.model.visitors.Substitutor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.utils.addIfNotNull
class SubstitutingFunctor(
@@ -31,13 +34,7 @@ class SubstitutingFunctor(
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
if (basicEffects.isEmpty()) return emptyList()
val receiver =
listOfNotNull(ownerFunction.dispatchReceiverParameter?.toESVariable(), ownerFunction.extensionReceiverParameter?.toESVariable())
val parameters = receiver + ownerFunction.valueParameters.map { it.toESVariable() }
assert(parameters.size == arguments.size) {
"Arguments and parameters size mismatch: arguments.size = ${arguments.size}, parameters.size = ${parameters.size}"
}
val parameters = computeParameters(arguments)
val substitutions = parameters.zip(arguments).toMap()
val substitutor = Substitutor(substitutions, typeSubstitution, reducer)
@@ -61,6 +58,38 @@ class SubstitutingFunctor(
return substitutedClauses
}
private fun computeParameters(arguments: List<Computation>): List<ESVariable> {
val dispatchReceiver = ownerFunction.dispatchReceiverParameter?.toESVariable()
val extensionReceiver = ownerFunction.extensionReceiverParameter?.toESVariable()
val receivers = listOfNotNull(dispatchReceiver, extensionReceiver)
val valueParameters = ownerFunction.valueParameters.map { it.toESVariable() }
val parameters = receivers + valueParameters
if (parameters.size == arguments.size) {
return parameters
}
fun fail(): Nothing {
error("Arguments and parameters size mismatch: arguments.size = ${arguments.size}, parameters.size = ${parameters.size}")
}
val dispatchParameterDescriptor = dispatchReceiver?.descriptor ?: fail()
if (dispatchParameterDescriptor is ReceiverParameterDescriptor) {
val classDescriptor = (dispatchParameterDescriptor.value as? ImplicitClassReceiver)?.classDescriptor ?: fail()
if (classDescriptor.kind == ClassKind.OBJECT) {
val parametersWithoutDispatch = buildList {
extensionReceiver?.let { add(it) }
addAll(valueParameters)
}
if (parametersWithoutDispatch.size != arguments.size) {
fail()
}
return parametersWithoutDispatch
}
}
fail()
}
private fun combine(effect: SimpleEffect, substitutedCondition: ESEffect): ESEffect? {
if (substitutedCondition !is ConditionalEffect) return null
@@ -0,0 +1,38 @@
// FIR_IDENTICAL
// ISSUE: KT-51704
import Foo.Companion.checkSomethingCompanion
import Bar.checkSomethingObject
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
class Foo {
companion object {
@OptIn(ExperimentalContracts::class)
fun checkSomethingCompanion(condition: Boolean, message: String) {
contract {
returns() implies (condition)
}
if (!condition)
throw Exception(message)
}
}
}
object Bar {
@OptIn(ExperimentalContracts::class)
fun checkSomethingObject(condition: Boolean, message: String) {
contract {
returns() implies (condition)
}
if (!condition)
throw Exception(message)
}
}
fun usage() {
Foo.checkSomethingCompanion(1 == 2, "wat") // ok
checkSomethingCompanion(1 == 2, "wat") // compiler crash
Bar.checkSomethingObject(1 == 2, "wat") // ok
checkSomethingObject(1 == 2, "wat") // compiler crash
}
@@ -0,0 +1,31 @@
package
public fun usage(): kotlin.Unit
public object Bar {
private constructor Bar()
@kotlin.OptIn(markerClass = {kotlin.contracts.ExperimentalContracts::class}) public final fun checkSomethingObject(/*0*/ condition: kotlin.Boolean, /*1*/ message: kotlin.String): kotlin.Unit
Returns(WILDCARD) -> condition
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Foo {
public constructor Foo()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public companion object Companion {
private constructor Companion()
@kotlin.OptIn(markerClass = {kotlin.contracts.ExperimentalContracts::class}) public final fun checkSomethingCompanion(/*0*/ condition: kotlin.Boolean, /*1*/ message: kotlin.String): kotlin.Unit
Returns(WILDCARD) -> condition
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -35837,6 +35837,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/externalArguments.kt");
}
@Test
@TestMetadata("functionInCompanion.kt")
public void testFunctionInCompanion() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/functionInCompanion.kt");
}
@Test
@TestMetadata("intersectingInfo.kt")
public void testIntersectingInfo() throws Exception {