[NI] Perform full type checking in NI if there is no contradiction

In NI type checking actually performs in constraint system. To be conservative, now we still perform full type cheking but only if there is no contradiction in constraint system
This commit is contained in:
Mikhail Zarechenskiy
2017-08-09 11:13:00 +03:00
parent f51f7a0fe4
commit 82d43c23b6
4 changed files with 27 additions and 12 deletions
@@ -199,14 +199,15 @@ class KotlinToResolvedCallTransformer(
// todo external argument // todo external argument
val argumentExpression = valueArgument.getArgumentExpression() ?: continue val argumentExpression = valueArgument.getArgumentExpression() ?: continue
updateRecordedType(argumentExpression, newContext) updateRecordedType(argumentExpression, newContext, resolvedCall.isReallySuccess())
} }
} }
fun updateRecordedType( fun updateRecordedType(
expression: KtExpression, expression: KtExpression,
context: BasicCallResolutionContext context: BasicCallResolutionContext,
reportErrorForTypeMismatch: Boolean
): KotlinType? { ): KotlinType? {
val deparenthesized = expression.let { val deparenthesized = expression.let {
KtPsiUtil.getLastElementDeparenthesized(it, context.statementFilter) KtPsiUtil.getLastElementDeparenthesized(it, context.statementFilter)
@@ -225,7 +226,7 @@ class KotlinToResolvedCallTransformer(
updatedType = updateRecordedTypeForArgument(updatedType, recordedType, expression, context) updatedType = updateRecordedTypeForArgument(updatedType, recordedType, expression, context)
dataFlowAnalyzer.checkType(updatedType, deparenthesized, context) dataFlowAnalyzer.checkType(updatedType, deparenthesized, context, reportErrorForTypeMismatch)
return updatedType return updatedType
} }
@@ -102,7 +102,7 @@ class ResolvedAtomCompleter(
.replaceBindingTrace(trace) .replaceBindingTrace(trace)
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext) kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
} }
} }
@@ -361,7 +361,8 @@ public class ControlStructureTypingUtils {
.replaceExpectedType(c.expectedType) .replaceExpectedType(c.expectedType)
.replaceDataFlowInfo(typeInfo.getDataFlowInfo()) .replaceDataFlowInfo(typeInfo.getDataFlowInfo())
.replaceBindingTrace(c.trace), .replaceBindingTrace(c.trace),
hasError hasError,
true
); );
return hasError.get(); return hasError.get();
} }
@@ -24,9 +24,9 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.config.LanguageFeature; import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.contracts.EffectSystem;
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.*;
@@ -252,7 +252,17 @@ public class DataFlowAnalyzer {
@Nullable @Nullable
public KotlinType checkType(@Nullable KotlinType expressionType, @NotNull KtExpression expression, @NotNull ResolutionContext context) { public KotlinType checkType(@Nullable KotlinType expressionType, @NotNull KtExpression expression, @NotNull ResolutionContext context) {
return checkType(expressionType, expression, context, null); return checkType(expressionType, expression, context, null, true);
}
@Nullable
public KotlinType checkType(
@Nullable KotlinType expressionType,
@NotNull KtExpression expression,
@NotNull ResolutionContext context,
boolean reportErrorForTypeMismatch
) {
return checkType(expressionType, expression, context, null, reportErrorForTypeMismatch);
} }
@NotNull @NotNull
@@ -265,14 +275,15 @@ public class DataFlowAnalyzer {
@NotNull KotlinType expressionType, @NotNull KotlinType expressionType,
@NotNull KtExpression expression, @NotNull KtExpression expression,
@NotNull ResolutionContext c, @NotNull ResolutionContext c,
@NotNull Ref<Boolean> hasError @NotNull Ref<Boolean> hasError,
boolean reportErrorForTypeMismatch
) { ) {
if (noExpectedType(c.expectedType) || !c.expectedType.getConstructor().isDenotable() || if (noExpectedType(c.expectedType) || !c.expectedType.getConstructor().isDenotable() ||
KotlinTypeChecker.DEFAULT.isSubtypeOf(expressionType, c.expectedType)) { KotlinTypeChecker.DEFAULT.isSubtypeOf(expressionType, c.expectedType)) {
return expressionType; return expressionType;
} }
if (expression instanceof KtConstantExpression) { if (expression instanceof KtConstantExpression && reportErrorForTypeMismatch) {
ConstantValue<?> constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, c.trace, c.expectedType); ConstantValue<?> constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, c.trace, c.expectedType);
boolean error = new CompileTimeConstantChecker(c, builtIns, true) boolean error = new CompileTimeConstantChecker(c, builtIns, true)
.checkConstantExpressionType(constantValue, (KtConstantExpression) expression, c.expectedType); .checkConstantExpressionType(constantValue, (KtConstantExpression) expression, c.expectedType);
@@ -288,7 +299,8 @@ public class DataFlowAnalyzer {
SmartCastResult castResult = checkPossibleCast(expressionType, expression, c); SmartCastResult castResult = checkPossibleCast(expressionType, expression, c);
if (castResult != null) return castResult.getResultType(); if (castResult != null) return castResult.getResultType();
if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(c, expression, c.expectedType, expressionType) && if (reportErrorForTypeMismatch &&
!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(c, expression, c.expectedType, expressionType) &&
!DiagnosticUtilsKt.reportTypeMismatchDueToScalaLikeNamedFunctionSyntax(c, expression, c.expectedType, expressionType)) { !DiagnosticUtilsKt.reportTypeMismatchDueToScalaLikeNamedFunctionSyntax(c, expression, c.expectedType, expressionType)) {
c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType)); c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType));
} }
@@ -301,7 +313,8 @@ public class DataFlowAnalyzer {
@Nullable KotlinType expressionType, @Nullable KotlinType expressionType,
@NotNull KtExpression expressionToCheck, @NotNull KtExpression expressionToCheck,
@NotNull ResolutionContext c, @NotNull ResolutionContext c,
@Nullable Ref<Boolean> hasError @Nullable Ref<Boolean> hasError,
boolean reportErrorForTypeMismatch
) { ) {
if (hasError == null) { if (hasError == null) {
hasError = Ref.create(false); hasError = Ref.create(false);
@@ -315,7 +328,7 @@ public class DataFlowAnalyzer {
if (expressionType == null) return null; if (expressionType == null) return null;
KotlinType result = checkTypeInternal(expressionType, expression, c, hasError); KotlinType result = checkTypeInternal(expressionType, expression, c, hasError, reportErrorForTypeMismatch);
if (Boolean.FALSE.equals(hasError.get())) { if (Boolean.FALSE.equals(hasError.get())) {
for (AdditionalTypeChecker checker : additionalTypeCheckers) { for (AdditionalTypeChecker checker : additionalTypeCheckers) {
checker.checkType(expression, expressionType, result, c); checker.checkType(expression, expressionType, result, c);