Effects: support assert-like contracts
- Support functions that explicitly express relation between successfull return and passed arguments (e.g., 'check') - Note that we have to correct resulting data flow for arguments *after* resoling (because we get contracts only after resolving). To do so, we have to extend MutableDataFlowInfoForArguments interface with 'updateResultInfo' method. ========== Introduction of EffectSystem: 11/18
This commit is contained in:
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.contracts.EffectSystem
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.CONSTRAINT_SYSTEM_COMPLETER
|
||||
@@ -47,6 +48,7 @@ import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -61,7 +63,8 @@ class CallCompleter(
|
||||
private val callCheckers: Iterable<CallChecker>,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val effectSystem: EffectSystem
|
||||
) {
|
||||
fun <D : CallableDescriptor> completeCall(
|
||||
context: BasicCallResolutionContext,
|
||||
@@ -131,6 +134,7 @@ class CallCompleter(
|
||||
) {
|
||||
if (resolvedCall == null || resolvedCall.isCompleted || resolvedCall.constraintSystem == null) {
|
||||
completeArguments(context, results)
|
||||
resolvedCall?.updateResultDataFlowInfoUsingEffects(context.trace)
|
||||
resolvedCall?.markCallAsCompleted()
|
||||
return
|
||||
}
|
||||
@@ -140,6 +144,7 @@ class CallCompleter(
|
||||
completeArguments(context, results)
|
||||
|
||||
resolvedCall.updateResolutionStatusFromConstraintSystem(context, tracing)
|
||||
resolvedCall.updateResultDataFlowInfoUsingEffects(context.trace)
|
||||
resolvedCall.markCallAsCompleted()
|
||||
}
|
||||
|
||||
@@ -393,4 +398,14 @@ class CallCompleter(
|
||||
val expressionType = trace.getType(expression.receiverExpression)
|
||||
return expressionType != null && TypeUtils.isNullableType(expressionType)
|
||||
}
|
||||
|
||||
private fun MutableResolvedCall<*>.updateResultDataFlowInfoUsingEffects(bindingTrace: BindingTrace) {
|
||||
if (dataFlowInfoForArguments is MutableDataFlowInfoForArguments.WithoutArgumentsCheck) return
|
||||
|
||||
val moduleDescriptor = DescriptorUtils.getContainingModule(this.resultingDescriptor?.containingDeclaration ?: return)
|
||||
val resultDFIfromES = effectSystem.getDataFlowInfoForFinishedCall(this, bindingTrace, moduleDescriptor)
|
||||
dataFlowInfoForArguments.updateResultInfo(resultDFIfromES)
|
||||
|
||||
effectSystem.recordDefiniteInvocations(this, bindingTrace, moduleDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -82,4 +82,12 @@ public class DataFlowInfoForArgumentsImpl extends MutableDataFlowInfoForArgument
|
||||
if (resultInfo == null) return initialDataFlowInfo;
|
||||
return initialDataFlowInfo.and(resultInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateResultInfo(@NotNull DataFlowInfo dataFlowInfo) {
|
||||
if (dataFlowInfo.equals(DataFlowInfo.Companion.getEMPTY())) return;
|
||||
|
||||
if (resultInfo == null) resultInfo = initialDataFlowInfo;
|
||||
resultInfo = resultInfo.and(dataFlowInfo);
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -29,6 +29,7 @@ public abstract class MutableDataFlowInfoForArguments implements DataFlowInfoFor
|
||||
}
|
||||
|
||||
public abstract void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo);
|
||||
public abstract void updateResultInfo(@NotNull DataFlowInfo dataFlowInfo);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -47,6 +48,11 @@ public abstract class MutableDataFlowInfoForArguments implements DataFlowInfoFor
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateResultInfo(@NotNull DataFlowInfo dataFlowInfo) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
|
||||
|
||||
+3
@@ -206,6 +206,9 @@ public class ControlStructureTypingUtils {
|
||||
dataFlowInfoForArgumentsMap.put(valueArgument, dataFlowInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateResultInfo(@NotNull DataFlowInfo dataFlowInfo) { }
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
|
||||
|
||||
Reference in New Issue
Block a user