Refactor language features, which control effect system

- Introduce new language feature 'ReadDeserializedContracts', which
allows to deserialize contracts from metadata.

- Introduce new language feature 'AllowContractsForCustomFunctions',
which allows reading contracts from sources.

- Use new features instead of combination 'CallsInPlaceEffect ||
ReturnsEffect'

- Rename 'CallsInPlaceEffect' -> 'UseCallsInPlaceEffect',
'ReturnsEffect' -> 'UseReturnsEffect'. As names suggest, they control
if it is allowed to use corresponding effect in analysis.

We have to introduce separate 'ReadDeserializedContracts' to enable
contracts only in some modules of the project, because libraries are
read with project-wide settings (see KT-20692).
This commit is contained in:
Dmitry Savvinov
2018-01-24 21:17:16 +03:00
parent 78850087be
commit b29a6e48fb
100 changed files with 116 additions and 206 deletions
@@ -1048,7 +1048,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
mark(lambdaExpression)
val functionLiteral = lambdaExpression.functionLiteral
// NB. Behaviour here is implicitly controlled by the LanguageFeature 'CallsInPlaceEffect'
// NB. Behaviour here is implicitly controlled by the LanguageFeature 'UseCallsInPlaceEffect'
// If this feature is turned off, then slice LAMBDA_INVOCATIONS is never written and invocationKind
// in all subsequent calls always 'null', resulting in falling back to old behaviour
visitFunction(functionLiteral, trace[BindingContext.LAMBDA_INVOCATIONS, lambdaExpression])
@@ -38,7 +38,7 @@ class ContractDeserializerImpl(private val configuration: DeserializationConfigu
): Pair<FunctionDescriptor.UserDataKey<*>, LazyContractProvider>? {
if (!proto.hasContract()) return null
if (!configuration.returnsEffectAllowed && !configuration.callsInPlaceEffectAllowed) return null
if (!configuration.readDeserializedContracts) return null
val worker = ContractDeserializationWorker(typeTable, typeDeserializer, ownerFunction)
val contract = worker.deserializeContract(proto.contract)
@@ -45,7 +45,7 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
bindingTrace: BindingTrace,
moduleDescriptor: ModuleDescriptor
): DataFlowInfo {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return DataFlowInfo.EMPTY
if (!languageVersionSettings.supportsFeature(LanguageFeature.UseReturnsEffect)) return DataFlowInfo.EMPTY
// Prevent launch of effect system machinery on pointless cases (constants/enums/constructors/etc.)
val callExpression = resolvedCall.call.callElement as? KtCallExpression ?: return DataFlowInfo.EMPTY
@@ -62,7 +62,7 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
bindingTrace: BindingTrace,
moduleDescriptor: ModuleDescriptor
): ConditionalDataFlowInfo {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return ConditionalDataFlowInfo.EMPTY
if (!languageVersionSettings.supportsFeature(LanguageFeature.UseReturnsEffect)) return ConditionalDataFlowInfo.EMPTY
if (leftExpression == null || rightExpression == null) return ConditionalDataFlowInfo.EMPTY
val leftComputation =
@@ -82,7 +82,7 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
}
fun recordDefiniteInvocations(resolvedCall: ResolvedCall<*>, bindingTrace: BindingTrace, moduleDescriptor: ModuleDescriptor) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect)) return
if (!languageVersionSettings.supportsFeature(LanguageFeature.UseCallsInPlaceEffect)) return
// Prevent launch of effect system machinery on pointless cases (constants/enums/constructors/etc.)
val callExpression = resolvedCall.call.callElement as? KtCallExpression ?: return
@@ -102,7 +102,7 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
bindingTrace: BindingTrace,
moduleDescriptor: ModuleDescriptor
): DataFlowInfo {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return DataFlowInfo.EMPTY
if (!languageVersionSettings.supportsFeature(LanguageFeature.UseReturnsEffect)) return DataFlowInfo.EMPTY
if (condition == null) return DataFlowInfo.EMPTY
return getContextInfoWhen(ESReturns(value.lift()), condition, bindingTrace, moduleDescriptor)
@@ -43,8 +43,7 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
if (!isContractDescriptionCallFastCheck(expression) || ownerDescriptor !is FunctionDescriptor) return
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey) ?: return
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect) ||
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.AllowContractsForCustomFunctions) ||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
languageVersionSettings.getFlag(AnalysisFlag.Flags.allowKotlinPackage)
@@ -31,7 +31,5 @@ class CompilerDeserializationConfiguration(languageVersionSettings: LanguageVers
override val isJvmPackageNameSupported = languageVersionSettings.supportsFeature(LanguageFeature.JvmPackageName)
override val returnsEffectAllowed: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)
override val callsInPlaceEffectAllowed: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect)
override val readDeserializedContracts: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.ReadDeserializedContracts)
}
@@ -235,8 +235,7 @@ class FunctionDescriptorResolver(
}
val emptyContract = LazyContractProvider.createInitialized(null)
val isContractsEnabled = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect) ||
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
val isContractsEnabled = languageVersionSettings.supportsFeature(LanguageFeature.AllowContractsForCustomFunctions) ||
// We need to enable contracts if we're compiling "kotlin"-package to be able to ship contracts in stdlib in 1.2
languageVersionSettings.getFlag(AnalysisFlag.allowKotlinPackage)