Type approximation factored out as an additional checker

This commit is contained in:
Andrey Breslav
2015-02-03 12:32:55 +03:00
parent a35c6b1566
commit 29d24374d6
3 changed files with 65 additions and 41 deletions
@@ -16,13 +16,10 @@
package org.jetbrains.kotlin.resolve
import org.jetbrains.annotations.ReadOnly
import java.util.Collections
import kotlin.properties.Delegates
import org.jetbrains.kotlin.resolve.calls.checkers.*
private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker())
private val DEFAULT_TYPE_CHECKERS = listOf(TypeApproximator())
public abstract class AdditionalCheckerProvider(
public val annotationCheckers: List<AnnotationChecker>,
@@ -30,7 +27,7 @@ public abstract class AdditionalCheckerProvider(
) {
public val callCheckers: List<CallChecker> = DEFAULT_CALL_CHECKERS + additionalCallCheckers
public val additionalTypeCheckers: List<AdditionalTypeChecker> = listOf()
public val additionalTypeCheckers: List<AdditionalTypeChecker> = DEFAULT_TYPE_CHECKERS
public object DefaultProvider : AdditionalCheckerProvider(listOf(), listOf()) {}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.resolve.calls.checkers
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
import org.jetbrains.kotlin.types.getApproximationTo
import org.jetbrains.kotlin.types.Approximation
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.resolve.BindingContext
import kotlin.properties.Delegates
public class TypeApproximator : AdditionalTypeChecker {
override fun checkType(expression: JetExpression, expressionType: JetType, c: ResolutionContext<*>) {
if (noExpectedType(c.expectedType)) return
val approximationInfo = expressionType.getApproximationTo(
c.expectedType,
object : Approximation.DataFlowExtras {
override val canBeNull: Boolean
get() = c.dataFlowInfo.getNullability(dataFlowValue).canBeNull()
override val possibleTypes: Set<JetType>
get() = c.dataFlowInfo.getPossibleTypes(dataFlowValue)
override val presentableText: String
get() = StringUtil.trimMiddle(expression.getText(), 50)
private val dataFlowValue =
DataFlowValueFactory.createDataFlowValue(expression, expressionType, c.trace.getBindingContext())
}
)
if (approximationInfo != null) {
c.trace.record(BindingContext.EXPRESSION_RESULT_APPROXIMATION, expression, approximationInfo)
}
}
}
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.types.expressions;
import com.google.common.collect.Sets;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -37,11 +36,13 @@ import org.jetbrains.kotlin.resolve.constants.CompileTimeConstantChecker;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.resolve.constants.evaluate.EvaluatePackage;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.JetTypeInfo;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.TypesPackage;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import java.util.Collection;
import java.util.Set;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
@@ -161,50 +162,22 @@ public class DataFlowUtils {
@Nullable
public static JetType checkType(
@Nullable final JetType expressionType,
@Nullable JetType expressionType,
@NotNull JetExpression expressionToCheck,
@NotNull final ResolutionContext c,
@NotNull ResolutionContext c,
@Nullable Ref<Boolean> hasError
) {
if (hasError != null) hasError.set(false);
final JetExpression expression = JetPsiUtil.safeDeparenthesize(expressionToCheck, false);
JetExpression expression = JetPsiUtil.safeDeparenthesize(expressionToCheck, false);
recordExpectedType(c.trace, expression, c.expectedType);
if (expressionType == null) return null;
c.additionalTypeChecker.checkType(expression, expressionType, c);
if (noExpectedType(c.expectedType) || !c.expectedType.getConstructor().isDenotable() ||
JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, c.expectedType)) {
if (!noExpectedType(c.expectedType)) {
Approximation.Info approximationInfo = TypesPackage.getApproximationTo(expressionType, c.expectedType,
new Approximation.DataFlowExtras() {
private DataFlowValue getDataFlowValue() {
return DataFlowValueFactory.createDataFlowValue(expression, expressionType, c.trace.getBindingContext());
}
@Override
public boolean getCanBeNull() {
return c.dataFlowInfo.getNullability(getDataFlowValue()).canBeNull();
}
@Override
public Set<JetType> getPossibleTypes() {
return c.dataFlowInfo.getPossibleTypes(getDataFlowValue());
}
@NotNull
@Override
public String getPresentableText() {
return StringUtil.trimMiddle(expression.getText(), 50);
}
}
);
if (approximationInfo != null) {
c.trace.record(BindingContext.EXPRESSION_RESULT_APPROXIMATION, expression, approximationInfo);
}
}
return expressionType;
}