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.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.contracts.description.BooleanExpression
|
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.ContractDescription
|
||||||
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
|
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
|
||||||
import org.jetbrains.kotlin.contracts.description.expressions.BooleanVariableReference
|
import org.jetbrains.kotlin.contracts.description.expressions.BooleanVariableReference
|
||||||
@@ -69,8 +70,9 @@ internal class PsiContractParserDispatcher(
|
|||||||
return null
|
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
|
if (effects.isEmpty()) return null
|
||||||
|
|
||||||
return ContractDescription(effects, callContext.functionDescriptor, storageManager)
|
return ContractDescription(effects, callContext.functionDescriptor, storageManager)
|
||||||
@@ -92,6 +94,19 @@ internal class PsiContractParserDispatcher(
|
|||||||
return parser.tryParseEffect(expression)
|
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 {
|
private fun isValidEffectDeclaration(expression: KtExpression): Boolean {
|
||||||
if (expression !is KtCallExpression && expression !is KtBinaryExpression) {
|
if (expression !is KtCallExpression && expression !is KtBinaryExpression) {
|
||||||
collector.badDescription("unexpected construction in contract description", expression)
|
collector.badDescription("unexpected construction in contract description", expression)
|
||||||
|
|||||||
+2
-3
@@ -6,7 +6,6 @@
|
|||||||
* SECTIONS: contracts, declarations, contractBuilder, effects, callsInPlace
|
* SECTIONS: contracts, declarations, contractBuilder, effects, callsInPlace
|
||||||
* NUMBER: 2
|
* NUMBER: 2
|
||||||
* DESCRIPTION: functions with contract and duplicate CallsInPlace.
|
* DESCRIPTION: functions with contract and duplicate CallsInPlace.
|
||||||
* UNEXPECTED BEHAVIOUR
|
|
||||||
* ISSUES: KT-26150
|
* ISSUES: KT-26150
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -16,7 +15,7 @@ import kotlin.contracts.*
|
|||||||
inline fun case_1(block: () -> Unit) {
|
inline fun case_1(block: () -> Unit) {
|
||||||
contract {
|
contract {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
<!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, InvocationKind.EXACTLY_ONCE)<!>
|
||||||
}
|
}
|
||||||
return block()
|
return block()
|
||||||
}
|
}
|
||||||
@@ -25,7 +24,7 @@ inline fun case_1(block: () -> Unit) {
|
|||||||
inline fun case_2(block: () -> Unit) {
|
inline fun case_2(block: () -> Unit) {
|
||||||
contract {
|
contract {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
|
<!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, InvocationKind.AT_MOST_ONCE)<!>
|
||||||
}
|
}
|
||||||
return block()
|
return block()
|
||||||
}
|
}
|
||||||
|
|||||||
-5
@@ -1,9 +1,4 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public inline fun case_1(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
|
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
|
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