[FIR] Use argument mapping from resolved call for contract argument mapping

This commit is contained in:
Dmitriy Novozhilov
2020-04-14 12:33:33 +03:00
parent 5b660d2457
commit c71f9d9640
4 changed files with 71 additions and 7 deletions
@@ -0,0 +1,29 @@
import kotlin.contracts.*
fun foo(x: Any, y: Any) {
contract {
returns() implies (x is Int && y is String)
}
if (x !is Int || y !is String) {
throw IllegalStateException()
}
}
fun test_1(x: Any, y: Any) {
foo(x = x, y = y)
x.inc()
y.length
}
fun test_2(x: Any, y: Any) {
foo(x, y = y)
x.inc()
y.length
}
fun test_3(x: Any, y: Any) {
foo(y = y, x = x)
x.inc()
y.length
}
@@ -0,0 +1,30 @@
FILE: namedArguments.kt
public final fun foo(x: R|kotlin/Any|, y: R|kotlin/Any|): R|kotlin/Unit|
[R|Contract description]
<
Returns(WILDCARD) -> x is kotlin/Int && y is kotlin/String
>
{
[StubStatement]
when () {
(R|<local>/x| !is R|kotlin/Int|) || (R|<local>/y| !is R|kotlin/String|) -> {
throw R|java/lang/IllegalStateException.IllegalStateException|()
}
}
}
public final fun test_1(x: R|kotlin/Any|, y: R|kotlin/Any|): R|kotlin/Unit| {
R|/foo|(x = R|<local>/x|, y = R|<local>/y|)
R|<local>/x|.R|kotlin/Int.inc|()
R|<local>/y|.R|kotlin/String.length|
}
public final fun test_2(x: R|kotlin/Any|, y: R|kotlin/Any|): R|kotlin/Unit| {
R|/foo|(R|<local>/x|, y = R|<local>/y|)
R|<local>/x|.R|kotlin/Int.inc|()
R|<local>/y|.R|kotlin/String.length|
}
public final fun test_3(x: R|kotlin/Any|, y: R|kotlin/Any|): R|kotlin/Unit| {
R|/foo|(y = R|<local>/y|, x = R|<local>/x|)
R|<local>/x|.R|kotlin/Int.inc|()
R|<local>/y|.R|kotlin/String.length|
}
@@ -593,6 +593,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/returnsImplies/eqNotEq.kt");
}
@TestMetadata("namedArguments.kt")
public void testNamedArguments() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/returnsImplies/namedArguments.kt");
}
@TestMetadata("propertyAccessors.kt")
public void testPropertyAccessors() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/returnsImplies/propertyAccessors.kt");
@@ -92,12 +92,10 @@ fun createArgumentsMapping(qualifiedAccess: FirQualifiedAccess): Map<Int, FirExp
when (qualifiedAccess) {
is FirFunctionCall -> {
val function = qualifiedAccess.toResolvedCallableSymbol()?.fir as? FirSimpleFunction ?: return null
val nameToIndex = function.valueParameters.mapIndexed { index, parameter -> parameter.name to index }.toMap()
qualifiedAccess.arguments.forEachIndexed { index, argument ->
when (argument) {
is FirNamedArgumentExpression -> argumentsMapping[nameToIndex[argument.name]!!] = argument
else -> argumentsMapping[index] = argument
}
val parameterToIndex = function.valueParameters.mapIndexed { index, parameter -> parameter to index }.toMap()
val callArgumentMapping = qualifiedAccess.argumentMapping ?: return null
for (argument in qualifiedAccess.arguments) {
argumentsMapping[parameterToIndex.getValue(callArgumentMapping.getValue(argument))] = argument.unwrap()
}
}
is FirVariableAssignment -> {
@@ -105,4 +103,6 @@ fun createArgumentsMapping(qualifiedAccess: FirQualifiedAccess): Map<Int, FirExp
}
}
return argumentsMapping
}
}
private fun FirExpression.unwrap(): FirExpression = if (this is FirWrappedArgumentExpression) expression else this