Prohibit declaring multiple callsInPlace contract on same lambda.
#KT-26150 fixed
This commit is contained in:
+17
-2
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.contracts.parsing
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.contracts.description.BooleanExpression
|
||||
import org.jetbrains.kotlin.contracts.description.CallsEffectDeclaration
|
||||
import org.jetbrains.kotlin.contracts.description.ContractDescription
|
||||
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
|
||||
import org.jetbrains.kotlin.contracts.description.expressions.BooleanVariableReference
|
||||
@@ -69,8 +70,9 @@ internal class PsiContractParserDispatcher(
|
||||
return null
|
||||
}
|
||||
|
||||
val effects = lambda.bodyExpression?.statements?.mapNotNull { parseEffect(it) } ?: return null
|
||||
|
||||
val effectsWithExpression = lambda.bodyExpression?.statements?.map { parseEffect(it) to it } ?: return null
|
||||
checkDuplicatedCallsEffectsAndReport(effectsWithExpression)
|
||||
val effects = effectsWithExpression.mapNotNull { it.first }
|
||||
if (effects.isEmpty()) return null
|
||||
|
||||
return ContractDescription(effects, callContext.functionDescriptor, storageManager)
|
||||
@@ -92,6 +94,19 @@ internal class PsiContractParserDispatcher(
|
||||
return parser.tryParseEffect(expression)
|
||||
}
|
||||
|
||||
private fun checkDuplicatedCallsEffectsAndReport(effects: List<Pair<EffectDeclaration?, KtExpression>>) {
|
||||
val descriptorsWithCallsEffect = mutableSetOf<ParameterDescriptor>()
|
||||
for ((effect, expression) in effects) {
|
||||
if (effect !is CallsEffectDeclaration) continue
|
||||
val descriptor = effect.variableReference.descriptor
|
||||
if (descriptor in descriptorsWithCallsEffect) {
|
||||
collector.badDescription("Duplicated contract for ${descriptor.name}. Only one `callsInPlace` contract per parameter is allowed.", expression)
|
||||
} else {
|
||||
descriptorsWithCallsEffect.add(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidEffectDeclaration(expression: KtExpression): Boolean {
|
||||
if (expression !is KtCallExpression && expression !is KtBinaryExpression) {
|
||||
collector.badDescription("unexpected construction in contract description", expression)
|
||||
|
||||
+2
-3
@@ -6,7 +6,6 @@
|
||||
* SECTIONS: contracts, declarations, contractBuilder, effects, callsInPlace
|
||||
* NUMBER: 2
|
||||
* DESCRIPTION: functions with contract and duplicate CallsInPlace.
|
||||
* UNEXPECTED BEHAVIOUR
|
||||
* ISSUES: KT-26150
|
||||
*/
|
||||
|
||||
@@ -16,7 +15,7 @@ import kotlin.contracts.*
|
||||
inline fun case_1(block: () -> Unit) {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, InvocationKind.EXACTLY_ONCE)<!>
|
||||
}
|
||||
return block()
|
||||
}
|
||||
@@ -25,7 +24,7 @@ inline fun case_1(block: () -> Unit) {
|
||||
inline fun case_2(block: () -> Unit) {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, InvocationKind.AT_MOST_ONCE)<!>
|
||||
}
|
||||
return block()
|
||||
}
|
||||
|
||||
-5
@@ -1,9 +1,4 @@
|
||||
package
|
||||
|
||||
public inline fun case_1(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
|
||||
CallsInPlace(block, EXACTLY_ONCE)
|
||||
CallsInPlace(block, EXACTLY_ONCE)
|
||||
|
||||
public inline fun case_2(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
|
||||
CallsInPlace(block, EXACTLY_ONCE)
|
||||
CallsInPlace(block, AT_MOST_ONCE)
|
||||
|
||||
Reference in New Issue
Block a user