Effects: support contracts with conditional returns

Support functions which have explicitly expressed relation between
return-value and arguments. If we have observed that function returned
this value, get additional information from effect system.

==========
Effect System introduction: 10/18
This commit is contained in:
Dmitry Savvinov
2017-10-03 15:02:40 +03:00
parent 87b0bc43d5
commit 72b0d31329
2 changed files with 17 additions and 4 deletions
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt; import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.contracts.EffectSystem;
import org.jetbrains.kotlin.incremental.KotlinLookupLocation; import org.jetbrains.kotlin.incremental.KotlinLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
@@ -59,6 +60,7 @@ public class DataFlowAnalyzer {
private final SmartCastManager smartCastManager; private final SmartCastManager smartCastManager;
private final ExpressionTypingFacade facade; private final ExpressionTypingFacade facade;
private final LanguageVersionSettings languageVersionSettings; private final LanguageVersionSettings languageVersionSettings;
private final EffectSystem effectSystem;
public DataFlowAnalyzer( public DataFlowAnalyzer(
@NotNull Iterable<AdditionalTypeChecker> additionalTypeCheckers, @NotNull Iterable<AdditionalTypeChecker> additionalTypeCheckers,
@@ -66,7 +68,8 @@ public class DataFlowAnalyzer {
@NotNull KotlinBuiltIns builtIns, @NotNull KotlinBuiltIns builtIns,
@NotNull SmartCastManager smartCastManager, @NotNull SmartCastManager smartCastManager,
@NotNull ExpressionTypingFacade facade, @NotNull ExpressionTypingFacade facade,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull EffectSystem effectSystem
) { ) {
this.additionalTypeCheckers = additionalTypeCheckers; this.additionalTypeCheckers = additionalTypeCheckers;
this.constantExpressionEvaluator = constantExpressionEvaluator; this.constantExpressionEvaluator = constantExpressionEvaluator;
@@ -74,6 +77,7 @@ public class DataFlowAnalyzer {
this.smartCastManager = smartCastManager; this.smartCastManager = smartCastManager;
this.facade = facade; this.facade = facade;
this.languageVersionSettings = languageVersionSettings; this.languageVersionSettings = languageVersionSettings;
this.effectSystem = effectSystem;
} }
// NB: use this method only for functions from 'Any' // NB: use this method only for functions from 'Any'
@@ -234,10 +238,16 @@ public class DataFlowAnalyzer {
} }
} }
}); });
DataFlowInfo infoFromEffectSystem = effectSystem.extractDataFlowInfoFromCondition(
condition, conditionValue, context.trace, DescriptorUtils.getContainingModule(context.scope.getOwnerDescriptor())
);
if (result.get() == null) { if (result.get() == null) {
return context.dataFlowInfo; return context.dataFlowInfo.and(infoFromEffectSystem);
} }
return context.dataFlowInfo.and(result.get());
return context.dataFlowInfo.and(result.get()).and(infoFromEffectSystem);
} }
@Nullable @Nullable
@@ -368,8 +368,11 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
override fun visitWhenConditionWithExpression(condition: KtWhenConditionWithExpression) { override fun visitWhenConditionWithExpression(condition: KtWhenConditionWithExpression) {
val expression = condition.expression val expression = condition.expression
if (expression != null) { if (expression != null) {
newDataFlowInfo = checkTypeForExpressionCondition( val basicDataFlowInfo = checkTypeForExpressionCondition(
context, expression, subjectType, subjectExpression == null, subjectDataFlowValue) context, expression, subjectType, subjectExpression == null, subjectDataFlowValue)
val moduleDescriptor = DescriptorUtils.getContainingModule(context.scope.ownerDescriptor)
val dataFlowInfoFromES = components.effectSystem.getDataFlowInfoWhenEquals(subjectExpression, expression, context.trace, moduleDescriptor)
newDataFlowInfo = basicDataFlowInfo.and(dataFlowInfoFromES)
} }
} }