From 2c0ef592e65bc2108b0513a06978076f1a1392ea Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Tue, 3 Oct 2017 15:02:34 +0300 Subject: [PATCH] Effects: add DSL for declaration of contracts - Introduce DSL for declaration of contracts. Functions and classes in this DSL do not bear any computational semantics: in fact, they all do not exist on runtime. Whole work of extracting semantics from such calls is done by special parts of compiler - To make distinguishing those declarations more robust and convenient, introduce internal annotation @ContractsDSL - Turn off InlineChecker inside contracts DSL. We do this, because some functions from DSL should take any possible lambda, so we can't write any type besides 'Function'. However, InlineChecker will complain if we will pass inlined lambda in such function -- though, this is false positive because we know that functions from contracts DSL will never be executed - Change testData on HierarchyTestWithLib, where new enum from kotlin.internal changed expected output ========== Effect System introduction: 7/18 --- .../resolve/calls/checkers/InlineChecker.kt | 6 +++ .../withLib/enum/Enum_verification.xml | 11 ++--- .../stdlib/src/kotlin/internal/Annotations.kt | 6 +++ .../internal/contracts/ContractBuilder.kt | 40 ++++++++++++++++++ .../src/kotlin/internal/contracts/Effect.kt | 41 +++++++++++++++++++ 5 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 libraries/stdlib/src/kotlin/internal/contracts/ContractBuilder.kt create mode 100644 libraries/stdlib/src/kotlin/internal/contracts/Effect.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.kt index 984a79b0ef3..1f35462ea13 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.contracts.parsing.isFromContractDsl import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfType @@ -59,10 +60,15 @@ internal class InlineChecker(private val descriptor: FunctionDescriptor) : CallC override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { val expression = resolvedCall.call.calleeExpression ?: return + supportDefaultValueInline = context.languageVersionSettings.supportsFeature(LanguageFeature.InlineDefaultFunctionalParameters) //checking that only invoke or inlinable extension called on function parameter val targetDescriptor = resolvedCall.resultingDescriptor + + // Omit inline checks for 'contract'-call because those calls will never be executed, so inline checking is pointless + if (targetDescriptor.isFromContractDsl()) return + checkCallWithReceiver(context, targetDescriptor, resolvedCall.dispatchReceiver, expression) checkCallWithReceiver(context, targetDescriptor, resolvedCall.extensionReceiver, expression) diff --git a/idea/testData/hierarchy/withLib/enum/Enum_verification.xml b/idea/testData/hierarchy/withLib/enum/Enum_verification.xml index 69cc65b0426..2a196e101f2 100644 --- a/idea/testData/hierarchy/withLib/enum/Enum_verification.xml +++ b/idea/testData/hierarchy/withLib/enum/Enum_verification.xml @@ -9,9 +9,11 @@ - - + + + + @@ -22,9 +24,8 @@ - - - + + diff --git a/libraries/stdlib/src/kotlin/internal/Annotations.kt b/libraries/stdlib/src/kotlin/internal/Annotations.kt index d4d057d2b36..76e74713b7a 100644 --- a/libraries/stdlib/src/kotlin/internal/Annotations.kt +++ b/libraries/stdlib/src/kotlin/internal/Annotations.kt @@ -102,3 +102,9 @@ internal enum class RequireKotlinVersionKind { COMPILER_VERSION, API_VERSION, } + +/** + * Specifies that this declaration is a part of special DSL, used for constructing function's contract. + */ +@Retention(AnnotationRetention.BINARY) +internal annotation class ContractsDsl diff --git a/libraries/stdlib/src/kotlin/internal/contracts/ContractBuilder.kt b/libraries/stdlib/src/kotlin/internal/contracts/ContractBuilder.kt new file mode 100644 index 00000000000..bad8fff5906 --- /dev/null +++ b/libraries/stdlib/src/kotlin/internal/contracts/ContractBuilder.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.internal.contracts + +import kotlin.internal.ContractsDsl +import kotlin.internal.InlineOnly + +@ContractsDsl +internal interface ContractBuilder { + @ContractsDsl fun returns(): Returns + @ContractsDsl fun returns(value: Any?): Returns + @ContractsDsl fun returnsNotNull(): ReturnsNotNull + @ContractsDsl fun callsInPlace(lambda: Function, kind: InvocationKind = InvocationKind.UNKNOWN): CallsInPlace +} + +@ContractsDsl +internal enum class InvocationKind { + @ContractsDsl AT_MOST_ONCE, + @ContractsDsl AT_LEAST_ONCE, + @ContractsDsl EXACTLY_ONCE, + @ContractsDsl UNKNOWN +} + +@ContractsDsl +@InlineOnly +internal inline fun contract(builder: ContractBuilder.() -> Unit) { } \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/internal/contracts/Effect.kt b/libraries/stdlib/src/kotlin/internal/contracts/Effect.kt new file mode 100644 index 00000000000..3b2b20532ab --- /dev/null +++ b/libraries/stdlib/src/kotlin/internal/contracts/Effect.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.internal.contracts + +import kotlin.internal.ContractsDsl + +@ContractsDsl +internal interface Effect + +@ContractsDsl +internal interface ConditionalEffect : Effect + +@ContractsDsl +internal interface SimpleEffect { + @ContractsDsl + infix fun implies(booleanExpression: Boolean): ConditionalEffect +} + + +@ContractsDsl +internal interface Returns : SimpleEffect + +@ContractsDsl +internal interface ReturnsNotNull : SimpleEffect + +@ContractsDsl +internal interface CallsInPlace : SimpleEffect \ No newline at end of file