Refactoring of JetTypeInfo / BindingContext. Loop data flow analysis corrected.

Now BindingContext includes expression type info instead of jump out possible, data flow info and expression type.
getType() was added into BindingContext, getType() and recordType() were added into BindingTrace.
JetTypeInfo now includes also jump possible flag and jump point data flow info.
Old TypeInfoWithJumpInfo deleted.
TypeInfoFactory introduced to create JetTypeInfo instances.
A pack of extra tests for break / continue in loops added.
This commit is contained in:
Mikhail Glukhikh
2015-04-20 16:12:49 +03:00
parent 14b92404cd
commit 27625b04e1
113 changed files with 908 additions and 550 deletions
@@ -376,14 +376,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
@NotNull
public Type expressionType(JetExpression expression) {
public Type expressionType(@Nullable JetExpression expression) {
JetType type = expressionJetType(expression);
return type == null ? Type.VOID_TYPE : asmType(type);
}
@Nullable
public JetType expressionJetType(JetExpression expression) {
return bindingContext.get(EXPRESSION_TYPE, expression);
public JetType expressionJetType(@Nullable JetExpression expression) {
return expression != null ? bindingContext.getType(expression) : null;
}
@Override
@@ -534,7 +534,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
JetExpression loopRange = forExpression.getLoopRange();
JetType loopRangeType = bindingContext.get(EXPRESSION_TYPE, loopRange);
JetType loopRangeType = bindingContext.getType(loopRange);
assert loopRangeType != null;
Type asmLoopRangeType = asmType(loopRangeType);
if (asmLoopRangeType.getSort() == Type.ARRAY) {
@@ -818,7 +818,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
private ForInArrayLoopGenerator(@NotNull JetForExpression forExpression) {
super(forExpression);
loopRangeType = bindingContext.get(EXPRESSION_TYPE, forExpression.getLoopRange());
loopRangeType = bindingContext.getType(forExpression.getLoopRange());
}
@Override
@@ -1029,7 +1029,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Override
protected void storeRangeStartAndEnd() {
JetType loopRangeType = bindingContext.get(EXPRESSION_TYPE, forExpression.getLoopRange());
JetType loopRangeType = bindingContext.getType(forExpression.getLoopRange());
assert loopRangeType != null;
Type asmLoopRangeType = asmType(loopRangeType);
gen(forExpression.getLoopRange(), asmLoopRangeType);
@@ -1061,7 +1061,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
incrementVar = createLoopTempVariable(asmElementType);
JetType loopRangeType = bindingContext.get(EXPRESSION_TYPE, forExpression.getLoopRange());
JetType loopRangeType = bindingContext.getType(forExpression.getLoopRange());
assert loopRangeType != null;
Type asmLoopRangeType = asmType(loopRangeType);
@@ -1286,7 +1286,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
public static CompileTimeConstant getCompileTimeConstant(@NotNull JetExpression expression, @NotNull BindingContext bindingContext) {
CompileTimeConstant<?> compileTimeValue = bindingContext.get(COMPILE_TIME_VALUE, expression);
if (compileTimeValue instanceof IntegerValueTypeConstant) {
JetType expectedType = bindingContext.get(EXPRESSION_TYPE, expression);
JetType expectedType = bindingContext.getType(expression);
assert expectedType != null : "Expression is not type checked: " + expression.getText();
return EvaluatePackage.createCompileTimeConstantWithType((IntegerValueTypeConstant) compileTimeValue, expectedType);
}
@@ -2664,7 +2664,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
public StackValue visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, StackValue data) {
checkReflectionIsAvailable(expression);
JetType type = bindingContext.get(EXPRESSION_TYPE, expression);
JetType type = bindingContext.getType(expression);
assert type != null;
assert state.getReflectionTypes().getkClass().getTypeConstructor().equals(type.getConstructor())
@@ -3384,7 +3384,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
JetExpression initializer = multiDeclaration.getInitializer();
if (initializer == null) return StackValue.none();
JetType initializerType = bindingContext.get(EXPRESSION_TYPE, initializer);
JetType initializerType = bindingContext.getType(initializer);
assert initializerType != null;
Type initializerAsmType = asmType(initializerType);
@@ -3491,7 +3491,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
public StackValue generateNewArray(@NotNull JetCallExpression expression) {
JetType arrayType = bindingContext.get(EXPRESSION_TYPE, expression);
JetType arrayType = bindingContext.getType(expression);
assert arrayType != null : "Array instantiation isn't type checked: " + expression.getText();
return generateNewArray(expression, arrayType);
@@ -3531,7 +3531,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Override
public StackValue visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, StackValue receiver) {
JetExpression array = expression.getArrayExpression();
JetType type = bindingContext.get(EXPRESSION_TYPE, array);
JetType type = bindingContext.getType(array);
Type arrayType = expressionType(array);
List<JetExpression> indices = expression.getIndexExpressions();
FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(REFERENCE_TARGET, expression);
@@ -3640,7 +3640,7 @@ The "returned" value of try expression with no finally is either the last expres
(or blocks).
*/
JetType jetType = bindingContext.get(EXPRESSION_TYPE, expression);
JetType jetType = bindingContext.getType(expression);
assert jetType != null;
final Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType);
@@ -3808,7 +3808,7 @@ The "returned" value of try expression with no finally is either the last expres
v.dup();
Label nonnull = new Label();
v.ifnonnull(nonnull);
JetType leftType = bindingContext.get(EXPRESSION_TYPE, left);
JetType leftType = bindingContext.getType(left);
assert leftType != null;
genThrow(v, "kotlin/TypeCastException", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(leftType) +
" cannot be cast to " +
@@ -3847,7 +3847,7 @@ The "returned" value of try expression with no finally is either the last expres
if (expressionToMatch != null) {
Type subjectType = expressionToMatch.type;
markStartLineNumber(patternExpression);
JetType condJetType = bindingContext.get(EXPRESSION_TYPE, patternExpression);
JetType condJetType = bindingContext.getType(patternExpression);
Type condType;
if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
assert condJetType != null;
@@ -4051,7 +4051,7 @@ The "returned" value of try expression with no finally is either the last expres
if (rangeExpression instanceof JetBinaryExpression) {
JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression;
if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) {
JetType jetType = bindingContext.get(EXPRESSION_TYPE, rangeExpression);
JetType jetType = bindingContext.getType(rangeExpression);
assert jetType != null;
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
return INTEGRAL_RANGES.contains(descriptor);
@@ -1266,7 +1266,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
result.addField((JetDelegatorByExpressionSpecifier) specifier, propertyDescriptor);
}
else {
JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
JetType expressionType = bindingContext.getType(expression);
Type asmType =
expressionType != null ? typeMapper.mapType(expressionType) : typeMapper.mapType(getSuperClass(specifier));
result.addField((JetDelegatorByExpressionSpecifier) specifier, asmType, "$delegate_" + n);
@@ -1718,7 +1718,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
DelegationFieldsInfo.Field field = delegationFieldsInfo.getInfo((JetDelegatorByExpressionSpecifier) specifier);
generateDelegateField(field);
JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
JetType delegateExpressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression);
JetType delegateExpressionType = bindingContext.getType(delegateExpression);
generateDelegates(getSuperClass(specifier), delegateExpressionType, field);
}
}
@@ -395,7 +395,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
private JetType getPropertyOrDelegateType(@NotNull JetProperty property, @NotNull PropertyDescriptor descriptor) {
JetExpression delegateExpression = property.getDelegateExpression();
if (delegateExpression != null) {
JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression);
JetType delegateType = bindingContext.getType(delegateExpression);
assert delegateType != null : "Type of delegate expression should be recorded";
return delegateType;
}
@@ -283,7 +283,7 @@ public class PropertyCodegen {
}
private void generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor) {
JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, p.getDelegateExpression());
JetType delegateType = bindingContext.getType(p.getDelegateExpression());
if (delegateType == null) {
// If delegate expression is unresolved reference
delegateType = ErrorUtils.createErrorType("Delegate type");
@@ -515,7 +515,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
int fieldNumber = mappings.size();
JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getSubjectExpression());
JetType type = bindingContext.getType(expression.getSubjectExpression());
assert type != null : "should not be null in a valid when by enums";
ClassDescriptor classDescriptor = (ClassDescriptor) type.getConstructor().getDeclarationDescriptor();
assert classDescriptor != null : "because it's enum";
@@ -32,8 +32,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import java.util.*;
import static org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE;
abstract public class SwitchCodegen {
protected final JetWhenExpression expression;
protected final boolean isStatement;
@@ -132,7 +130,7 @@ abstract public class SwitchCodegen {
}
protected void generateNullCheckIfNeeded() {
JetType subjectJetType = bindingContext.get(EXPRESSION_TYPE, expression.getSubjectExpression());
JetType subjectJetType = bindingContext.getType(expression.getSubjectExpression());
assert subjectJetType != null : "subject type can't be null (i.e. void)";
@@ -216,7 +216,7 @@ public class JavaNullabilityWarningsChecker : AdditionalTypeChecker {
is JetPostfixExpression ->
if (expression.getOperationToken() == JetTokens.EXCLEXCL) {
val baseExpression = expression.getBaseExpression()
val baseExpressionType = c.trace.get(BindingContext.EXPRESSION_TYPE, baseExpression) ?: return
val baseExpressionType = c.trace.getType(baseExpression) ?: return
doIfNotNull(
DataFlowValueFactory.createDataFlowValue(baseExpression, baseExpressionType, c),
c
@@ -228,7 +228,7 @@ public class JavaNullabilityWarningsChecker : AdditionalTypeChecker {
when (expression.getOperationToken()) {
JetTokens.ELVIS -> {
val baseExpression = expression.getLeft()
val baseExpressionType = c.trace.get(BindingContext.EXPRESSION_TYPE, baseExpression) ?: return
val baseExpressionType = c.trace.getType(baseExpression) ?: return
doIfNotNull(
DataFlowValueFactory.createDataFlowValue(baseExpression, baseExpressionType, c),
c
@@ -243,7 +243,7 @@ public class JavaNullabilityWarningsChecker : AdditionalTypeChecker {
if (expression.getLeft() != null && expression.getRight() != null) {
SenselessComparisonChecker.checkSenselessComparisonWithNull(
expression, expression.getLeft()!!, expression.getRight()!!, c,
{ c.trace.get(BindingContext.EXPRESSION_TYPE, it) },
{ c.trace.getType(it) },
{
value ->
doIfNotNull(value, c) { Nullability.NOT_NULL } ?: Nullability.UNKNOWN
@@ -23,12 +23,12 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.types.JetTypeInfo
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.expressions.JetTypeInfo
public fun JetExpression.computeTypeInfoInContext(
scope: JetScope,
@@ -59,7 +59,7 @@ public fun JetExpression.computeTypeInContext(
expectedType: JetType = TypeUtils.NO_EXPECTED_TYPE,
module: ModuleDescriptor = scope.getModule()
): JetType {
return computeTypeInfoInContext(scope, trace, dataFlowInfo, expectedType, module).getType().safeType(this)
return computeTypeInfoInContext(scope, trace, dataFlowInfo, expectedType, module).type.safeType(this)
}
public fun JetType?.safeType(expression: JetExpression): JetType {
@@ -190,7 +190,7 @@ public class JetControlFlowProcessor {
return;
}
JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
JetType type = trace.getBindingContext().getType(expression);
if (type != null && KotlinBuiltIns.isNothing(type)) {
builder.jumpToError(expression);
}
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeUtils;
import static org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
public final class WhenChecker {
@@ -63,7 +62,7 @@ public final class WhenChecker {
@Nullable
private static JetType whenSubjectType(@NotNull JetWhenExpression expression, @NotNull BindingContext context) {
JetExpression subjectExpression = expression.getSubjectExpression();
return subjectExpression == null ? null : context.get(EXPRESSION_TYPE, subjectExpression);
return subjectExpression == null ? null : context.getType(subjectExpression);
}
private static boolean isWhenExhaustive(@NotNull JetWhenExpression expression, @NotNull BindingTrace trace) {
@@ -112,8 +111,7 @@ public final class WhenChecker {
for (JetWhenEntry entry : expression.getEntries()) {
for (JetWhenCondition condition : entry.getConditions()) {
if (condition instanceof JetWhenConditionWithExpression) {
JetType type = trace.getBindingContext().get(
EXPRESSION_TYPE, ((JetWhenConditionWithExpression) condition).getExpression()
JetType type = trace.getBindingContext().getType(((JetWhenConditionWithExpression) condition).getExpression()
);
if (type != null && KotlinBuiltIns.isNothingOrNullableNothing(type)) {
return true;
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilPackage;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
@@ -64,6 +65,16 @@ public class PseudocodeUtil {
return bindingContext.getKeys(slice);
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
return bindingContext.getType(expression);
}
@Override
public void recordType(@NotNull JetExpression expression, @Nullable JetType type) {
}
@Override
public void report(@NotNull Diagnostic diagnostic) {
}
@@ -196,7 +196,7 @@ public class DebugInfoUtil {
// if 'foo' in 'foo[i]' is unresolved it means 'foo[i]' is unresolved (otherwise 'foo[i]' is marked as 'missing unresolved')
markedWithError = true;
}
JetType expressionType = bindingContext.get(EXPRESSION_TYPE, expression);
JetType expressionType = bindingContext.getType(expression);
DiagnosticFactory<?> factory = markedWithErrorElements.get(expression);
if (declarationDescriptor != null &&
(ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))) {
@@ -280,7 +280,7 @@ public class AnnotationResolver {
@NotNull JetType expectedType,
@NotNull BindingTrace trace
) {
JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression);
JetType expressionType = trace.getType(argumentExpression);
if (expressionType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, expectedType)) {
// TYPE_MISMATCH should be reported otherwise
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.types.Approximation;
import org.jetbrains.kotlin.types.DeferredType;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.expressions.CaptureKind;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import org.jetbrains.kotlin.util.Box;
import org.jetbrains.kotlin.util.slicedMap.*;
@@ -73,6 +74,11 @@ public interface BindingContext {
public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
return ImmutableMap.of();
}
@Nullable
public JetType getType(@NotNull JetExpression expression) {
return null;
}
};
WritableSlice<AnnotationDescriptor, JetAnnotationEntry> ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT = Slices.createSimpleSlice();
@@ -82,18 +88,12 @@ public interface BindingContext {
WritableSlice<JetExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = Slices.createSimpleSlice();
WritableSlice<JetTypeReference, JetType> TYPE = Slices.createSimpleSlice();
WritableSlice<JetExpression, JetType> EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
WritableSlice<JetExpression, JetTypeInfo> EXPRESSION_TYPE_INFO = new BasicWritableSlice<JetExpression, JetTypeInfo>(DO_NOTHING);
WritableSlice<JetExpression, JetType> EXPECTED_EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
WritableSlice<JetFunction, JetType> EXPECTED_RETURN_TYPE = new BasicWritableSlice<JetFunction, JetType>(DO_NOTHING);
WritableSlice<JetExpression, DataFlowInfo> EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice<JetExpression, DataFlowInfo>(DO_NOTHING);
WritableSlice<JetExpression, Approximation.Info> EXPRESSION_RESULT_APPROXIMATION = new BasicWritableSlice<JetExpression, Approximation.Info>(DO_NOTHING);
WritableSlice<JetExpression, DataFlowInfo> DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice();
/**
* Expression has jump out of the loop (break/continue) inside
*/
WritableSlice<JetExpression, Boolean> EXPRESSION_JUMP_OUT_POSSIBLE = new BasicWritableSlice<JetExpression, Boolean>(DO_NOTHING);
/**
* A qualifier corresponds to a receiver expression (if any). For 'A.B' qualifier is recorded for 'A'.
*/
@@ -262,4 +262,7 @@ public interface BindingContext {
@TestOnly
@NotNull
<K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice);
@Nullable
JetType getType(@NotNull JetExpression expression);
}
@@ -24,14 +24,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.expressions.TypeInfoWithJumpInfo;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
import java.util.Collection;
@@ -81,6 +81,18 @@ public class BindingContextUtils {
return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key);
}
@NotNull
public static JetType getNotNullType(
@NotNull BindingContext bindingContext,
@NotNull JetExpression expression
) {
JetType result = bindingContext.getType(expression);
if (result == null) {
throw new IllegalStateException("Type must be not null for " + expression);
}
return result;
}
@NotNull
public static <K, V> V getNotNull(
@NotNull BindingContext bindingContext,
@@ -139,17 +151,16 @@ public class BindingContextUtils {
if (shouldBeMadeNullable) {
type = TypeUtils.makeNullable(type);
}
trace.record(BindingContext.EXPRESSION_TYPE, expression, type);
trace.recordType(expression, type);
return type;
}
@Nullable
public static TypeInfoWithJumpInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
if (!context.get(BindingContext.PROCESSED, expression)) return null;
DataFlowInfo dataFlowInfo = BindingContextUtilPackage.getDataFlowInfo(context, expression);
JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
Boolean jumpOutPossible = context.get(BindingContext.EXPRESSION_JUMP_OUT_POSSIBLE, expression);
return new TypeInfoWithJumpInfo(type, dataFlowInfo, Boolean.TRUE.equals(jumpOutPossible), dataFlowInfo);
public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
// NB: should never return null if expression is already processed
if (!Boolean.TRUE.equals(context.get(BindingContext.PROCESSED, expression))) return null;
JetTypeInfo result = context.get(BindingContext.EXPRESSION_TYPE_INFO, expression);
return result != null ? result : TypeInfoFactoryPackage.createTypeInfo(DataFlowInfo.EMPTY);
}
public static boolean isExpressionWithValidReference(
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
public fun JetReturnExpression.getTargetFunctionDescriptor(context: BindingContext): FunctionDescriptor? {
val targetLabel = getTargetLabel()
@@ -40,7 +41,7 @@ public fun JetReturnExpression.getTargetFunctionDescriptor(context: BindingConte
val containingFunctionDescriptor = DescriptorUtils.getParentOfType(declarationDescriptor, javaClass<FunctionDescriptor>(), false)
if (containingFunctionDescriptor == null) return null
return stream(containingFunctionDescriptor) { DescriptorUtils.getParentOfType(it, javaClass<FunctionDescriptor>()) }
return sequence(containingFunctionDescriptor) { DescriptorUtils.getParentOfType(it, javaClass<FunctionDescriptor>()) }
.dropWhile { it is AnonymousFunctionDescriptor }
.firstOrNull()
}
@@ -57,13 +58,17 @@ public fun <C : ResolutionContext<C>> ResolutionContext<C>.recordScopeAndDataFlo
if (expression == null) return
trace.record(BindingContext.RESOLUTION_SCOPE, expression, scope)
if (dataFlowInfo != DataFlowInfo.EMPTY) {
trace.record(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression, dataFlowInfo)
val typeInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)
if (typeInfo != null) {
trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo.replaceDataFlowInfo(dataFlowInfo))
}
else if (dataFlowInfo != DataFlowInfo.EMPTY) {
trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, createTypeInfo(dataFlowInfo))
}
}
public fun BindingContext.getDataFlowInfo(expression: JetExpression?): DataFlowInfo =
expression?.let { this[BindingContext.EXPRESSION_DATA_FLOW_INFO, it] } ?: DataFlowInfo.EMPTY
expression?.let { this[BindingContext.EXPRESSION_TYPE_INFO, it]?.dataFlowInfo } ?: DataFlowInfo.EMPTY
public fun JetExpression.isUnreachableCode(context: BindingContext): Boolean = context[BindingContext.UNREACHABLE_CODE, this]!!
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
@@ -40,4 +42,16 @@ public interface BindingTrace extends DiagnosticSink {
// slice.isCollective() must be true
@NotNull
<K, V> Collection<K> getKeys(WritableSlice<K, V> slice);
/**
* Expression type should be taken from EXPRESSION_TYPE_INFO slice
*/
@Nullable
JetType getType(@NotNull JetExpression expression);
/**
* Expression type should be recorded into EXPRESSION_TYPE_INFO slice
* (either updated old or a new one)
*/
void recordType(@NotNull JetExpression expression, @Nullable JetType type);
}
@@ -18,10 +18,15 @@ package org.jetbrains.kotlin.resolve;
import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import org.jetbrains.kotlin.util.slicedMap.*;
import java.util.Collection;
@@ -59,6 +64,12 @@ public class BindingTraceContext implements BindingTrace {
public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
return map.getSliceContents(slice);
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
return BindingTraceContext.this.getType(expression);
}
};
public BindingTraceContext() {
@@ -112,4 +123,18 @@ public class BindingTraceContext implements BindingTrace {
public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
return map.getKeys(slice);
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression);
return typeInfo != null ? typeInfo.getType() : null;
}
@Override
public void recordType(@NotNull JetExpression expression, @Nullable JetType type) {
JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression);
typeInfo = typeInfo != null ? typeInfo.replaceType(type) : TypeInfoFactoryPackage.createTypeInfo(type);
record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo);
}
}
@@ -22,11 +22,16 @@ import com.google.common.collect.ImmutableMap
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.psi.PsiElement
import com.intellij.openapi.util.ModificationTracker
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.types.JetType
public class CompositeBindingContext private (
private val delegates: List<BindingContext>
) : BindingContext {
override fun getType(expression: JetExpression): JetType? {
return delegates.sequence().map { it.getType(expression) }.firstOrNull { it != null }
}
companion object {
public fun create(delegates: List<BindingContext>): BindingContext {
@@ -37,7 +42,7 @@ public class CompositeBindingContext private (
}
override fun <K, V> get(slice: ReadOnlySlice<K, V>?, key: K?): V? {
return delegates.stream().map { it[slice, key] }.firstOrNull { it != null }
return delegates.sequence().map { it[slice, key] }.firstOrNull { it != null }
}
override fun <K, V> getKeys(slice: WritableSlice<K, V>?): Collection<K> {
@@ -265,7 +265,7 @@ public class DelegatedPropertyResolver {
builder.append("(");
List<JetType> argumentTypes = Lists.newArrayList();
for (ValueArgument argument : call.getValueArguments()) {
argumentTypes.add(context.get(EXPRESSION_TYPE, argument.getArgumentExpression()));
argumentTypes.add(context.getType(argument.getArgumentExpression()));
}
builder.append(Renderers.RENDER_COLLECTION_OF_TYPES.render(argumentTypes));
@@ -23,8 +23,12 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import org.jetbrains.kotlin.util.slicedMap.*;
import java.util.Collection;
@@ -51,6 +55,13 @@ public class DelegatingBindingTrace implements BindingTrace {
return DelegatingBindingTrace.this.get(slice, key);
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
return DelegatingBindingTrace.this.getType(expression);
}
@NotNull
@Override
public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
@@ -122,6 +133,25 @@ public class DelegatingBindingTrace implements BindingTrace {
return result;
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression);
return typeInfo != null ? typeInfo.getType() : null;
}
@Override
public void recordType(@NotNull JetExpression expression, @Nullable JetType type) {
JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression);
if (typeInfo == null) {
typeInfo = TypeInfoFactoryPackage.createTypeInfo(type);
}
else {
typeInfo = typeInfo.replaceType(type);
}
record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo);
}
public void addAllMyDataTo(@NotNull BindingTrace trace) {
addAllMyDataTo(trace, null, true);
}
@@ -18,7 +18,10 @@ package org.jetbrains.kotlin.resolve;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
@@ -74,6 +77,17 @@ public class ObservableBindingTrace implements BindingTrace {
return originalTrace.getKeys(slice);
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
return originalTrace.getType(expression);
}
@Override
public void recordType(@NotNull JetExpression expression, @Nullable JetType type) {
originalTrace.recordType(expression, type);
}
public <K, V> ObservableBindingTrace addHandler(@NotNull WritableSlice<K, V> slice, @NotNull RecordHandler<K, V> handler) {
handlers.put(slice, handler);
return this;
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.types.JetType;
public class TemporaryBindingTrace extends DelegatingBindingTrace {
@@ -37,11 +37,12 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.JetTypeInfo;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import javax.inject.Inject;
import java.util.Collections;
@@ -191,7 +192,7 @@ public class ArgumentTypeResolver {
@NotNull ResolveArgumentsMode resolveArgumentsMode
) {
if (expression == null) {
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
if (isFunctionLiteralArgument(expression, context)) {
return getFunctionLiteralTypeInfo(expression, getFunctionLiteralArgument(expression, context), context, resolveArgumentsMode);
@@ -214,7 +215,7 @@ public class ArgumentTypeResolver {
) {
if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
JetType type = getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, true);
return JetTypeInfo.create(type, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(type, context);
}
return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT));
}
@@ -297,7 +298,7 @@ public class ArgumentTypeResolver {
@NotNull ResolutionContext context,
@NotNull JetExpression expression
) {
JetType type = context.trace.get(BindingContext.EXPRESSION_TYPE, expression);
JetType type = context.trace.getType(expression);
if (type != null && !type.getConstructor().isDenotable()) {
if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor();
@@ -229,7 +229,7 @@ public class CallCompleter(
val deparenthesized = ArgumentTypeResolver.getLastElementDeparenthesized(expression, context)
if (deparenthesized == null) return
val recordedType = context.trace[BindingContext.EXPRESSION_TYPE, expression]
val recordedType = context.trace.getType(expression)
var updatedType: JetType? = recordedType
val results = completeCallForArgument(deparenthesized, context)
@@ -304,7 +304,7 @@ public class CallCompleter(
BindingContextUtils.updateRecordedType(
updatedType, expression, trace, /* shouldBeMadeNullable = */ hasNecessarySafeCall(expression, trace))
}
return trace[BindingContext.EXPRESSION_TYPE, argumentExpression]
return trace.getType(argumentExpression)
}
private fun hasNecessarySafeCall(expression: JetExpression, trace: BindingTrace): Boolean {
@@ -315,7 +315,7 @@ public class CallCompleter(
if (expression !is JetSafeQualifiedExpression) return false
//If a receiver type is not null, then this safe expression is useless, and we don't need to make the result type nullable.
val expressionType = trace[BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression()]
val expressionType = trace.getType(expression.getReceiverExpression())
return expressionType != null && TypeUtils.isNullableType(expressionType)
}
}
@@ -44,12 +44,9 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat
import org.jetbrains.kotlin.resolve.scopes.receivers.*;
import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.JetTypeInfo;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.expressions.BasicExpressionTypingVisitor;
import org.jetbrains.kotlin.types.expressions.DataFlowUtils;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
import org.jetbrains.kotlin.types.expressions.*;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import javax.inject.Inject;
import java.util.Collections;
@@ -136,14 +133,13 @@ public class CallExpressionResolver {
context, "trace to resolve as variable", nameExpression);
JetType type =
getVariableType(nameExpression, receiver, callOperationNode, context.replaceTraceAndCache(temporaryForVariable), result);
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
// TODO: for a safe call, it's necessary to set receiver != null here, as inside ArgumentTypeResolver.analyzeArgumentsAndRecordTypes
// Unfortunately it provokes problems with x?.y!!.foo() with the following x!!.bar():
// x != null proceeds to successive statements
if (result[0]) {
temporaryForVariable.commit();
return JetTypeInfo.create(type, dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(type, context);
}
Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
@@ -158,11 +154,11 @@ public class CallExpressionResolver {
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
return JetTypeInfo.create(type, dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(type, context);
}
temporaryForVariable.commit();
return JetTypeInfo.create(null, dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
@NotNull
@@ -172,7 +168,7 @@ public class CallExpressionResolver {
) {
JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context);
if (context.contextDependency == INDEPENDENT) {
DataFlowUtils.checkType(typeInfo, callExpression, context);
DataFlowUtils.checkType(typeInfo.getType(), callExpression, context);
}
return typeInfo;
}
@@ -205,7 +201,7 @@ public class CallExpressionResolver {
context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
}
if (functionDescriptor == null) {
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
if (functionDescriptor instanceof ConstructorDescriptor &&
DescriptorUtils.isAnnotationClass(functionDescriptor.getContainingDeclaration())) {
@@ -216,7 +212,7 @@ public class CallExpressionResolver {
JetType type = functionDescriptor.getReturnType();
return JetTypeInfo.create(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo());
return TypeInfoFactoryPackage.createTypeInfo(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo());
}
JetExpression calleeExpression = callExpression.getCalleeExpression();
@@ -230,11 +226,11 @@ public class CallExpressionResolver {
temporaryForVariable.commit();
context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression,
type != null ? type : ErrorUtils.createErrorType("")));
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
}
temporaryForFunction.commit();
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression) {
@@ -269,7 +265,7 @@ public class CallExpressionResolver {
else if (selectorExpression != null) {
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
}
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
/**
@@ -281,8 +277,8 @@ public class CallExpressionResolver {
private final DataFlowInfo safeCallChainInfo;
private JetTypeInfoInsideSafeCall(@Nullable JetType type, @NotNull DataFlowInfo dataFlowInfo, @Nullable DataFlowInfo safeCallChainInfo) {
super(type, dataFlowInfo);
private JetTypeInfoInsideSafeCall(@NotNull JetTypeInfo typeInfo, @Nullable DataFlowInfo safeCallChainInfo) {
super(typeInfo.getType(), typeInfo.getDataFlowInfo(), typeInfo.getJumpOutPossible(), typeInfo.getJumpFlowInfo());
this.safeCallChainInfo = safeCallChainInfo;
}
@@ -338,12 +334,13 @@ public class CallExpressionResolver {
if (selectorReturnType != null && !KotlinBuiltIns.isUnit(selectorReturnType)) {
if (TypeUtils.isNullableType(receiverType)) {
selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
selectorReturnTypeInfo = selectorReturnTypeInfo.replaceType(selectorReturnType);
}
}
}
// TODO : this is suspicious: remove this code?
if (selectorReturnType != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
if (selectorExpression != null && selectorReturnType != null) {
context.trace.recordType(selectorExpression, selectorReturnType);
}
CompileTimeConstant<?> value = ConstantExpressionEvaluator.evaluate(expression, context.trace, context.expectedType);
@@ -366,7 +363,7 @@ public class CallExpressionResolver {
// x?.foo(y!!)?.bar(x.field)?.gav(y.field) (like smartCasts\safecalls\longChain)
// Also, we should provide further safe call chain data flow information or
// if we are in the most left safe call then just take it from receiver
typeInfo = new JetTypeInfoInsideSafeCall(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo(), safeCallChainInfo);
typeInfo = new JetTypeInfoInsideSafeCall(selectorReturnTypeInfo, safeCallChainInfo);
}
else {
// Here we should not take selector data flow info into account because it's only one branch, see KT-7204
@@ -375,7 +372,7 @@ public class CallExpressionResolver {
// So we should just take safe call chain data flow information, e.g. foo(x!!)?.bar()?.gav()
// If it's null, we must take receiver normal info, it's a chain with length of one like foo(x!!)?.bar() and
// safe call chain information does not yet exist
typeInfo = JetTypeInfo.create(selectorReturnType, safeCallChainInfo);
typeInfo = selectorReturnTypeInfo.replaceDataFlowInfo(safeCallChainInfo);
}
}
else {
@@ -384,17 +381,16 @@ public class CallExpressionResolver {
if (context.insideCallChain || safeCallChainInfo == null) {
// Not a safe call inside call chain with safe calls OR
// call chain without safe calls at all
typeInfo = new JetTypeInfoInsideSafeCall(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo(),
selectorReturnTypeInfo.getDataFlowInfo());
typeInfo = new JetTypeInfoInsideSafeCall(selectorReturnTypeInfo, selectorReturnTypeInfo.getDataFlowInfo());
}
else {
// Exiting call chain with safe calls -- take data flow info from the lest-most receiver
// foo(x!!)?.bar().gav()
typeInfo = JetTypeInfo.create(selectorReturnType, safeCallChainInfo);
typeInfo = selectorReturnTypeInfo.replaceDataFlowInfo(safeCallChainInfo);
}
}
if (context.contextDependency == INDEPENDENT) {
DataFlowUtils.checkType(typeInfo, expression, context);
DataFlowUtils.checkType(typeInfo.getType(), expression, context);
}
return typeInfo;
}
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import javax.inject.Inject;
import java.util.*;
@@ -42,7 +42,6 @@ import java.util.List;
import java.util.Set;
import static org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE;
import static org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE;
import static org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST;
public class SmartCastUtils {
@@ -195,7 +194,7 @@ public class SmartCastUtils {
if (recordExpressionType) {
//TODO
//Why the expression type is rewritten for receivers and is not rewritten for arguments? Is it necessary?
trace.record(EXPRESSION_TYPE, expression, type);
trace.recordType(expression, type);
}
}
else {
@@ -69,7 +69,7 @@ public fun <C: ResolutionContext<C>> Call.hasUnresolvedArguments(context: Resolu
val arguments = getValueArguments().map { it?.getArgumentExpression() }
return arguments.any {
argument ->
val expressionType = context.trace.getBindingContext()[BindingContext.EXPRESSION_TYPE, argument]
val expressionType = argument?.let { context.trace.getBindingContext().getType(it) }
argument != null && !ArgumentTypeResolver.isFunctionLiteralArgument(argument, context)
&& (expressionType == null || expressionType.isError())
}
@@ -396,7 +396,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
}
override fun visitClassLiteralExpression(expression: JetClassLiteralExpression, expectedType: JetType?): CompileTimeConstant<*>? {
val jetType = trace.get(BindingContext.EXPRESSION_TYPE, expression)
val jetType = trace.getType(expression)
if (jetType.isError()) return null
return KClassValue(jetType)
}
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector
import org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE
import org.jetbrains.kotlin.resolve.BindingContext.QUALIFIER
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
import org.jetbrains.kotlin.resolve.BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT
@@ -153,7 +152,7 @@ private fun QualifierReceiver.resolveAsReceiverInQualifiedExpression(context: Ex
context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(referenceExpression, classifier))
}
else if (classifier is ClassDescriptor && classifier.hasClassObjectType) {
context.trace.record(EXPRESSION_TYPE, expression, classifier.classObjectType)
context.trace.recordType(expression, classifier.classObjectType)
}
}
@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.types.JetType
public class LockBasedLazyResolveStorageManager(private val storageManager: StorageManager): StorageManager by storageManager, LazyResolveStorageManager {
override fun <K, V> createSoftlyRetainedMemoizedFunction(compute: Function1<K, V>) =
@@ -38,6 +40,8 @@ public class LockBasedLazyResolveStorageManager(private val storageManager: Stor
LockProtectedTrace(storageManager, originalTrace)
private class LockProtectedContext(private val storageManager: StorageManager, private val context: BindingContext) : BindingContext {
override fun getType(expression: JetExpression): JetType? = storageManager.compute { context.getType(expression) }
override fun getDiagnostics(): Diagnostics = storageManager.compute { context.getDiagnostics() }
override fun <K, V> get(slice: ReadOnlySlice<K, V>, key: K) = storageManager.compute { context.get<K, V>(slice, key) }
@@ -49,6 +53,12 @@ public class LockBasedLazyResolveStorageManager(private val storageManager: Stor
}
private class LockProtectedTrace(private val storageManager: StorageManager, private val trace: BindingTrace) : BindingTrace {
override fun recordType(expression: JetExpression, type: JetType?) {
storageManager.compute { trace.recordType(expression, type) }
}
override fun getType(expression: JetExpression): JetType? = storageManager.compute { trace.getType(expression) }
private val context: BindingContext = LockProtectedContext(storageManager, trace.getBindingContext())
override fun getBindingContext() = context
@@ -1,53 +0,0 @@
/*
* 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.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
/**
* This class is intended to transfer data flow analysis information in bottom-up direction,
* from AST children to parents. It stores a type of expression under analysis,
* current information about types and nullabilities.
*
* NB: it must be immutable together with all its descendants!
*/
public class JetTypeInfo {
@NotNull
public static JetTypeInfo create(@Nullable JetType type, @NotNull DataFlowInfo dataFlowInfo) {
return new JetTypeInfo(type, dataFlowInfo);
}
private final JetType type;
private final DataFlowInfo dataFlowInfo;
protected JetTypeInfo(@Nullable JetType type, @NotNull DataFlowInfo dataFlowInfo) {
this.type = type;
this.dataFlowInfo = dataFlowInfo;
}
@Nullable
public JetType getType() {
return type;
}
@NotNull
public DataFlowInfo getDataFlowInfo() {
return dataFlowInfo;
}
}
@@ -87,6 +87,7 @@ import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType;
import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createCallForSpecialConstruction;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
import static org.jetbrains.kotlin.types.expressions.TypeReconstructionUtil.reconstructBareType;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
@SuppressWarnings("SuspiciousMethodCalls")
public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@@ -103,15 +104,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
// TODO : type substitutions???
CallExpressionResolver callExpressionResolver = components.expressionTypingServices.getCallExpressionResolver();
JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
JetType type = DataFlowUtils.checkType(typeInfo.getType(), expression, context);
return JetTypeInfo.create(type, typeInfo.getDataFlowInfo()); // TODO : Extensions to this
return typeInfo.checkType(expression, context); // TODO : Extensions to this
}
@Override
public JetTypeInfo visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, ExpressionTypingContext context) {
JetExpression innerExpression = expression.getExpression();
if (innerExpression == null) {
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
return facade.getTypeInfo(innerExpression, context.replaceScope(context.scope));
}
@@ -125,7 +125,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
boolean hasError = compileTimeConstantChecker.checkConstantExpressionType(value, expression, context.expectedType);
if (hasError) {
IElementType elementType = expression.getNode().getElementType();
return JetTypeInfo.create(components.expressionTypingUtils.getDefaultType(elementType), context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(components.expressionTypingUtils.getDefaultType(elementType), context);
}
}
@@ -140,15 +140,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetExpression left = expression.getLeft();
JetTypeReference right = expression.getRight();
if (right == null) {
JetTypeInfo leftTypeInfo = facade.getTypeInfo(left, contextWithNoExpectedType);
return JetTypeInfo.create(null, leftTypeInfo.getDataFlowInfo());
return facade.getTypeInfo(left, contextWithNoExpectedType).clearType();
}
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
boolean allowBareTypes = BARE_TYPES_ALLOWED.contains(operationType);
TypeResolutionContext typeResolutionContext = new TypeResolutionContext(context.scope, context.trace, true, allowBareTypes);
PossiblyBareType possiblyBareTarget = components.expressionTypingServices.getTypeResolver().resolvePossiblyBareType(typeResolutionContext, right);
PossiblyBareType possiblyBareTarget = components.expressionTypingServices.getTypeResolver().resolvePossiblyBareType(
typeResolutionContext, right);
if (operationType == JetTokens.COLON) {
// We do not allow bare types on static assertions, because static assertions provide an expected type for their argument,
@@ -158,26 +158,25 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType.replaceExpectedType(targetType));
checkBinaryWithTypeRHS(expression, context, targetType, typeInfo.getType());
return DataFlowUtils.checkType(targetType, expression, context, typeInfo.getDataFlowInfo());
return typeInfo.replaceType(targetType).checkType(expression, context);
}
JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType);
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
JetType subjectType = typeInfo.getType();
JetType targetType = reconstructBareType(right, possiblyBareTarget, subjectType, context.trace);
if (subjectType != null) {
checkBinaryWithTypeRHS(expression, contextWithNoExpectedType, targetType, subjectType);
dataFlowInfo = typeInfo.getDataFlowInfo();
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
if (operationType == AS_KEYWORD) {
DataFlowValue value = createDataFlowValue(left, subjectType, context);
dataFlowInfo = dataFlowInfo.establishSubtyping(value, targetType);
typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.establishSubtyping(value, targetType));
}
}
JetType result = operationType == AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType;
return DataFlowUtils.checkType(result, expression, context, dataFlowInfo);
return typeInfo.replaceType(result).checkType(expression, context);
}
private void checkBinaryWithTypeRHS(
@@ -251,10 +250,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
break;
case SUCCESS:
result = resolutionResult.getReceiverParameterDescriptor().getType();
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
context.trace.recordType(expression.getInstanceReference(), result);
break;
}
return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createCheckedTypeInfo(result, context, expression);
}
@Override
@@ -276,9 +275,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
case SUCCESS:
JetType result = checkPossiblyQualifiedSuper(expression, context, resolutionResult.getReceiverParameterDescriptor());
if (result != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
context.trace.recordType(expression.getInstanceReference(), result);
}
return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createCheckedTypeInfo(result, context, expression);
}
throw new IllegalStateException("Unknown code: " + resolutionResult.getCode());
}
@@ -288,7 +287,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (superTypeQualifier != null) {
components.expressionTypingServices.getTypeResolver().resolveType(context.scope, superTypeQualifier, context.trace, true);
}
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
private JetType checkPossiblyQualifiedSuper(
@@ -366,7 +365,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(SUPERCLASS_NOT_ACCESSIBLE_FROM_TRAIT.on(expression));
}
}
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
context.trace.recordType(expression.getInstanceReference(), result);
context.trace.record(BindingContext.REFERENCE_TARGET, expression.getInstanceReference(), result.getConstructor().getDeclarationDescriptor());
}
if (superTypeQualifier != null) {
@@ -456,12 +455,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (type != null && !type.isError()) {
JetType kClassType = components.reflectionTypes.getKClassType(Annotations.EMPTY, type);
if (!kClassType.isError()) {
return JetTypeInfo.create(kClassType, c.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(kClassType, c);
}
c.trace.report(REFLECTION_TYPES_NOT_LOADED.on(expression.getDoubleColonTokenReference()));
}
return JetTypeInfo.create(ErrorUtils.createErrorType("Unresolved class"), c.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(ErrorUtils.createErrorType("Unresolved class"), c);
}
@Nullable
@@ -551,11 +550,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (callableReference.getReferencedName().isEmpty()) {
c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference));
JetType errorType = ErrorUtils.createErrorType("Empty callable reference");
return DataFlowUtils.checkType(errorType, expression, c, c.dataFlowInfo);
return TypeInfoFactoryPackage.createCheckedTypeInfo(errorType, c, expression);
}
JetType result = getCallableReferenceType(expression, receiverType, c);
return DataFlowUtils.checkType(result, expression, c, c.dataFlowInfo);
return TypeInfoFactoryPackage.createCheckedTypeInfo(result, c, expression);
}
@Override
@@ -563,11 +562,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
DelegatingBindingTrace delegatingBindingTrace = context.trace.get(TRACE_DELTAS_CACHE, expression.getObjectDeclaration());
if (delegatingBindingTrace != null) {
delegatingBindingTrace.addAllMyDataTo(context.trace);
JetType type = context.trace.get(EXPRESSION_TYPE, expression);
return DataFlowUtils.checkType(type, expression, context, context.dataFlowInfo);
JetType type = context.trace.getType(expression);
return TypeInfoFactoryPackage.createCheckedTypeInfo(type, context, expression);
}
final JetType[] result = new JetType[1];
final TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve object literal expression", expression);
final TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace,
"trace to resolve object literal expression", expression);
ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor> handler = new ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor>() {
@Override
@@ -582,8 +582,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
});
result[0] = defaultType;
if (!context.trace.get(PROCESSED, expression)) {
temporaryTrace.record(EXPRESSION_TYPE, expression, defaultType);
if (Boolean.FALSE.equals(context.trace.get(PROCESSED, expression))) {
temporaryTrace.recordType(expression, defaultType);
temporaryTrace.record(PROCESSED, expression);
}
}
@@ -604,7 +604,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
temporaryTrace.addAllMyDataTo(cloneDelta);
context.trace.record(TRACE_DELTAS_CACHE, expression.getObjectDeclaration(), cloneDelta);
temporaryTrace.commit();
return DataFlowUtils.checkType(result[0], expression, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createCheckedTypeInfo(result[0], context, expression);
}
@Nullable
@@ -812,7 +812,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
: contextWithExpectedType.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE);
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo);
if (baseExpression == null) return TypeInfoFactoryPackage.createTypeInfo(context);
JetSimpleNameExpression operationSign = expression.getOperationReference();
@@ -829,13 +829,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
ExpressionReceiver receiver = new ExpressionReceiver(baseExpression, type);
Call call = CallMaker.makeCall(receiver, expression);
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
// Conventions for unary operations
Name name = OperatorConventions.UNARY_OPERATION_NAMES.get(operationType);
if (name == null) {
context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
return JetTypeInfo.create(null, dataFlowInfo);
return typeInfo.clearType();
}
// a[i]++/-- takes special treatment because it is actually let j = i, arr = a in arr.set(j, a.get(j).inc())
@@ -852,7 +851,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context, call, expression.getOperationReference(), name);
if (!resolutionResults.isSuccess()) {
return JetTypeInfo.create(null, dataFlowInfo);
return typeInfo.clearType();
}
// Computing the return type
@@ -888,7 +887,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
}
return DataFlowUtils.checkType(result, expression, contextWithExpectedType, dataFlowInfo);
return typeInfo.replaceType(result).checkType(expression, contextWithExpectedType);
}
@NotNull
@@ -903,7 +902,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
ArgumentTypeResolver.updateNumberType(expressionType, expression, context);
}
return DataFlowUtils.checkType(expressionType, expression, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createCheckedTypeInfo(expressionType, context, expression);
}
private JetTypeInfo visitExclExclExpression(@NotNull JetUnaryExpression expression, @NotNull ExpressionTypingContext context) {
@@ -929,19 +928,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
else {
DataFlowValue value = createDataFlowValue(baseExpression, baseType, context);
dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL);
baseTypeInfo = baseTypeInfo.replaceDataFlowInfo(dataFlowInfo.disequate(value, DataFlowValue.NULL));
}
// The call to checkType() is only needed here to execute additionalTypeCheckers, hence the NO_EXPECTED_TYPE
JetType resultingType = TypeUtils.makeNotNullable(baseType);
if (context.contextDependency == DEPENDENT) {
return JetTypeInfo.create(resultingType, dataFlowInfo);
return baseTypeInfo.replaceType(resultingType);
}
return DataFlowUtils.checkType(
resultingType,
expression,
context.replaceExpectedType(NO_EXPECTED_TYPE),
dataFlowInfo
);
// The call to checkType() is only needed here to execute additionalTypeCheckers, hence the NO_EXPECTED_TYPE
return baseTypeInfo.replaceType(resultingType).checkType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
}
@Override
@@ -958,13 +953,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
boolean isStatement
) {
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo);
if (baseExpression == null) return TypeInfoFactoryPackage.createTypeInfo(context);
return facade.getTypeInfo(baseExpression, context, isStatement);
}
private static boolean isKnownToBeNotNull(JetExpression expression, ExpressionTypingContext context) {
JetType type = context.trace.get(EXPRESSION_TYPE, expression);
JetType type = context.trace.getType(expression);
assert type != null : "This method is only supposed to be called when the type is not null";
return isKnownToBeNotNull(expression, type, context);
}
@@ -1073,7 +1068,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.record(REFERENCE_TARGET, operationSign, components.builtIns.getIdentityEquals());
ensureNonemptyIntersectionOfOperandTypes(expression, context);
// TODO : Check comparison pointlessness
result = JetTypeInfo.create(components.builtIns.getBooleanType(), context.dataFlowInfo);
result = TypeInfoFactoryPackage.createTypeInfo(components.builtIns.getBooleanType(), context);
}
else if (OperatorConventions.IN_OPERATIONS.contains(operationType)) {
ValueArgument leftArgument = CallMaker.makeValueArgument(left, left != null ? left : operationSign);
@@ -1084,7 +1079,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
else {
context.trace.report(UNSUPPORTED.on(operationSign, "Unknown operation"));
result = JetTypeInfo.create(null, context.dataFlowInfo);
result = TypeInfoFactoryPackage.createTypeInfo(context);
}
CompileTimeConstant<?> value = ConstantExpressionEvaluator.evaluate(
expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType
@@ -1092,7 +1087,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (value != null) {
return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
}
return DataFlowUtils.checkType(result, expression, contextWithExpectedType);
return result.checkType(expression, contextWithExpectedType);
}
private JetTypeInfo visitEquality(
@@ -1102,29 +1097,27 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
final JetExpression left,
final JetExpression right
) {
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
if (right == null || left == null) {
ExpressionTypingUtils.getTypeInfoOrNullType(right, context, facade);
ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
return JetTypeInfo.create(components.builtIns.getBooleanType(), dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(components.builtIns.getBooleanType(), context);
}
JetTypeInfo leftTypeInfo = getTypeInfoOrNullType(left, context, facade);
dataFlowInfo = leftTypeInfo.getDataFlowInfo();
DataFlowInfo dataFlowInfo = leftTypeInfo.getDataFlowInfo();
ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo);
JetTypeInfo rightTypeInfo = facade.getTypeInfo(right, contextWithDataFlow);
dataFlowInfo = rightTypeInfo.getDataFlowInfo();
TemporaryBindingTrace traceInterpretingRightAsNullableAny = TemporaryBindingTrace.create(
context.trace, "trace to resolve 'equals(Any?)' interpreting as of type Any? an expression:", right);
traceInterpretingRightAsNullableAny.record(EXPRESSION_TYPE, right, components.builtIns.getNullableAnyType());
traceInterpretingRightAsNullableAny.recordType(right, components.builtIns.getNullableAnyType());
// Nothing? has no members, and `equals()` would be unresolved on it
JetType leftType = leftTypeInfo.getType();
if (leftType != null && KotlinBuiltIns.isNothingOrNullableNothing(leftType)) {
traceInterpretingRightAsNullableAny.record(EXPRESSION_TYPE, left, components.builtIns.getNullableAnyType());
traceInterpretingRightAsNullableAny.recordType(left, components.builtIns.getNullableAnyType());
}
ExpressionTypingContext newContext = context.replaceBindingTrace(traceInterpretingRightAsNullableAny);
@@ -1144,7 +1137,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public boolean accept(@Nullable WritableSlice<?, ?> slice, Object key) {
// the type of the right (and sometimes left) expression isn't 'Any?' actually
if ((key == right || key == left) && slice == EXPRESSION_TYPE) return false;
if ((key == right || key == left) && slice == EXPRESSION_TYPE_INFO) return false;
// a hack due to KT-678
// without this line an smartcast is reported on the receiver (if it was previously checked for not-null)
@@ -1170,7 +1163,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(EQUALS_MISSING.on(operationSign));
}
}
return JetTypeInfo.create(components.builtIns.getBooleanType(), dataFlowInfo);
return rightTypeInfo.replaceType(components.builtIns.getBooleanType());
}
@NotNull
@@ -1180,7 +1173,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@NotNull JetSimpleNameExpression operationSign
) {
JetTypeInfo typeInfo = getTypeInfoForBinaryCall(OperatorConventions.COMPARE_TO, context, expression);
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
JetType compareToReturnType = typeInfo.getType();
JetType type = null;
if (compareToReturnType != null && !compareToReturnType.isError()) {
@@ -1191,7 +1183,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(COMPARE_TO_TYPE_MISMATCH.on(operationSign, compareToReturnType));
}
}
return JetTypeInfo.create(type, dataFlowInfo);
return typeInfo.replaceType(type);
}
@NotNull
@@ -1216,7 +1208,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (right != null) {
facade.getTypeInfo(right, contextForRightExpr);
}
return JetTypeInfo.create(booleanType, dataFlowInfo);
return leftTypeInfo.replaceType(booleanType);
}
@NotNull
@@ -1230,19 +1222,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (left == null || right == null) {
getTypeInfoOrNullType(left, context, facade);
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
Call call = createCallForSpecialConstruction(expression, expression.getOperationReference(), Lists.newArrayList(left, right));
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
call, "Elvis", Lists.newArrayList("left", "right"), Lists.newArrayList(true, false), contextWithExpectedType, null);
TypeInfoWithJumpInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext());
JetTypeInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext());
assert leftTypeInfo != null : "Left expression was not processed: " + expression;
JetType leftType = leftTypeInfo.getType();
if (leftType != null && isKnownToBeNotNull(left, leftType, context)) {
context.trace.report(USELESS_ELVIS.on(left, leftType));
}
TypeInfoWithJumpInfo rightTypeInfo = BindingContextUtils.getRecordedTypeInfo(right, context.trace.getBindingContext());
JetTypeInfo rightTypeInfo = BindingContextUtils.getRecordedTypeInfo(right, context.trace.getBindingContext());
assert rightTypeInfo != null : "Right expression was not processed: " + expression;
boolean loopBreakContinuePossible = leftTypeInfo.getJumpOutPossible() || rightTypeInfo.getJumpOutPossible();
JetType rightType = rightTypeInfo.getType();
@@ -1253,7 +1245,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL);
}
JetType type = resolvedCall.getResultingDescriptor().getReturnType();
if (type == null || rightType == null) return JetTypeInfo.create(null, dataFlowInfo);
if (type == null || rightType == null) return TypeInfoFactoryPackage.createTypeInfo(dataFlowInfo);
// Sometimes return type for special call for elvis operator might be nullable,
// but result is not nullable if the right type is not nullable
@@ -1261,11 +1253,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
type = TypeUtils.makeNotNullable(type);
}
if (context.contextDependency == DEPENDENT) {
return JetTypeInfo.create(type, dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(type, dataFlowInfo);
}
JetTypeInfo result = DataFlowUtils.checkType(type, expression, context, dataFlowInfo);
// If break or continue was possible, take condition check info as the jump info
return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), loopBreakContinuePossible, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkType(type, expression, context),
dataFlowInfo,
loopBreakContinuePossible,
context.dataFlowInfo);
}
@NotNull
@@ -1280,10 +1273,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
ExpressionTypingContext contextWithNoExpectedType = context.replaceExpectedType(NO_EXPECTED_TYPE);
if (right == null) {
if (left != null) facade.getTypeInfo(left, contextWithNoExpectedType);
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
DataFlowInfo dataFlowInfo = facade.getTypeInfo(right, contextWithNoExpectedType).getDataFlowInfo();
JetTypeInfo rightTypeInfo = facade.getTypeInfo(right, contextWithNoExpectedType);
DataFlowInfo dataFlowInfo = rightTypeInfo.getDataFlowInfo();
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, right, contextWithNoExpectedType);
ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo);
@@ -1298,9 +1292,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (left != null) {
dataFlowInfo = facade.getTypeInfo(left, contextWithDataFlow).getDataFlowInfo().and(dataFlowInfo);
rightTypeInfo = rightTypeInfo.replaceDataFlowInfo(dataFlowInfo);
}
return JetTypeInfo.create(resolutionResult.isSuccess() ? components.builtIns.getBooleanType() : null, dataFlowInfo);
if (resolutionResult.isSuccess()) {
return rightTypeInfo.replaceType(components.builtIns.getBooleanType());
}
else {
return rightTypeInfo.clearType();
}
}
private void ensureNonemptyIntersectionOfOperandTypes(JetBinaryExpression expression, final ExpressionTypingContext context) {
@@ -1350,13 +1350,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
private JetTypeInfo assignmentIsNotAnExpressionError(JetBinaryExpression expression, ExpressionTypingContext context) {
facade.checkStatementType(expression, context);
context.trace.report(ASSIGNMENT_IN_EXPRESSION_CONTEXT.on(expression));
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
@Override
public JetTypeInfo visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, ExpressionTypingContext context) {
JetTypeInfo typeInfo = resolveArrayAccessGetMethod(expression, context);
return DataFlowUtils.checkType(typeInfo, expression, context);
return resolveArrayAccessGetMethod(expression, context).checkType(expression, context);
}
@NotNull
@@ -1366,13 +1365,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@NotNull JetBinaryExpression binaryExpression
) {
JetExpression left = binaryExpression.getLeft();
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
JetTypeInfo typeInfo;
if (left != null) {
//left here is a receiver, so it doesn't depend on expected type
dataFlowInfo = facade.getTypeInfo(
left, context.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)).getDataFlowInfo();
typeInfo = facade.getTypeInfo(left, context.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE));
} else {
typeInfo = TypeInfoFactoryPackage.createTypeInfo(context);
}
ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo);
ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo());
OverloadResolutionResults<FunctionDescriptor> resolutionResults;
if (left != null) {
@@ -1387,17 +1387,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
if (resolutionResults.isSingleResult()) {
dataFlowInfo = resolutionResults.getResultingCall().getDataFlowInfoForArguments().getResultInfo();
typeInfo = typeInfo.replaceDataFlowInfo(resolutionResults.getResultingCall().getDataFlowInfoForArguments().getResultInfo());
}
return JetTypeInfo.create(OverloadResolutionResultsUtil.getResultingType(resolutionResults, context.contextDependency),
dataFlowInfo);
return typeInfo.replaceType(OverloadResolutionResultsUtil.getResultingType(resolutionResults, context.contextDependency));
}
@Override
public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) {
context.trace.report(DECLARATION_IN_ILLEGAL_CONTEXT.on(dcl));
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
@Override
@@ -1405,38 +1404,49 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (!JetPsiUtil.isLHSOfDot(expression)) {
context.trace.report(PACKAGE_IS_NOT_AN_EXPRESSION.on(expression));
}
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
private class StringTemplateVisitor extends JetVisitorVoid {
final ExpressionTypingContext context;
JetTypeInfo typeInfo;
StringTemplateVisitor(ExpressionTypingContext context) {
this.context = context;
this.typeInfo = TypeInfoFactoryPackage.createTypeInfo(context);
}
@Override
public void visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry) {
JetExpression entryExpression = entry.getExpression();
if (entryExpression != null) {
typeInfo = facade.getTypeInfo(entryExpression, context.replaceDataFlowInfo(typeInfo.getDataFlowInfo()));
}
}
@Override
public void visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry) {
CompileTimeConstantChecker.CharacterWithDiagnostic value = CompileTimeConstantChecker.escapedStringToCharacter(entry.getText(), entry);
Diagnostic diagnostic = value.getDiagnostic();
if (diagnostic != null) {
context.trace.report(diagnostic);
}
}
}
@Override
public JetTypeInfo visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression, ExpressionTypingContext contextWithExpectedType) {
final ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
final DataFlowInfo[] dataFlowInfo = new DataFlowInfo[] { context.dataFlowInfo };
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
StringTemplateVisitor visitor = new StringTemplateVisitor(context);
for (JetStringTemplateEntry entry : expression.getEntries()) {
entry.accept(new JetVisitorVoid() {
@Override
public void visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry) {
JetExpression entryExpression = entry.getExpression();
if (entryExpression != null) {
JetTypeInfo typeInfo = facade.getTypeInfo(entryExpression, context.replaceDataFlowInfo(dataFlowInfo[0]));
dataFlowInfo[0] = typeInfo.getDataFlowInfo();
}
}
@Override
public void visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry) {
CompileTimeConstantChecker.CharacterWithDiagnostic value = CompileTimeConstantChecker.escapedStringToCharacter(entry.getText(), entry);
Diagnostic diagnostic = value.getDiagnostic();
if (diagnostic != null) {
context.trace.report(diagnostic);
}
}
});
entry.accept(visitor);
}
ConstantExpressionEvaluator.evaluate(expression, context.trace, contextWithExpectedType.expectedType);
return DataFlowUtils.checkType(components.builtIns.getStringType(), expression, contextWithExpectedType, dataFlowInfo[0]);
return visitor.typeInfo.replaceType(components.builtIns.getStringType()).checkType(expression, contextWithExpectedType);
}
@Override
@@ -1450,7 +1460,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null) {
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
return facade.getTypeInfo(baseExpression, context, isStatement);
}
@@ -1458,7 +1468,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext context) {
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
@NotNull
@@ -1473,19 +1483,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@NotNull
private JetTypeInfo resolveArrayAccessSpecialMethod(@NotNull JetArrayAccessExpression arrayAccessExpression,
@Nullable JetExpression rightHandSide, //only for 'set' method
@NotNull ExpressionTypingContext oldContext,
@NotNull BindingTrace traceForResolveResult,
boolean isGet) {
@Nullable JetExpression rightHandSide, //only for 'set' method
@NotNull ExpressionTypingContext oldContext,
@NotNull BindingTrace traceForResolveResult,
boolean isGet) {
JetExpression arrayExpression = arrayAccessExpression.getArrayExpression();
if (arrayExpression == null) return JetTypeInfo.create(null, oldContext.dataFlowInfo);
if (arrayExpression == null) return TypeInfoFactoryPackage.createTypeInfo(oldContext);
JetTypeInfo arrayTypeInfo = facade.safeGetTypeInfo(arrayExpression, oldContext.replaceExpectedType(NO_EXPECTED_TYPE)
.replaceContextDependency(INDEPENDENT));
JetType arrayType = ExpressionTypingUtils.safeGetType(arrayTypeInfo);
DataFlowInfo dataFlowInfo = arrayTypeInfo.getDataFlowInfo();
ExpressionTypingContext context = oldContext.replaceDataFlowInfo(dataFlowInfo);
ExpressionTypingContext context = oldContext.replaceDataFlowInfo(arrayTypeInfo.getDataFlowInfo());
ExpressionReceiver receiver = new ExpressionReceiver(arrayExpression, arrayType);
if (!isGet) assert rightHandSide != null;
@@ -1497,19 +1507,21 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
List<JetExpression> indices = arrayAccessExpression.getIndexExpressions();
// The accumulated data flow info of all index expressions is saved on the last index
JetTypeInfo resultTypeInfo = arrayTypeInfo;
if (!indices.isEmpty()) {
dataFlowInfo = facade.getTypeInfo(indices.get(indices.size() - 1), context).getDataFlowInfo();
resultTypeInfo = facade.getTypeInfo(indices.get(indices.size() - 1), context);
}
if (!isGet) {
dataFlowInfo = facade.getTypeInfo(rightHandSide, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
resultTypeInfo = facade.getTypeInfo(rightHandSide, context);
}
if (!functionResults.isSingleResult()) {
traceForResolveResult.report(isGet ? NO_GET_METHOD.on(arrayAccessExpression) : NO_SET_METHOD.on(arrayAccessExpression));
return JetTypeInfo.create(null, dataFlowInfo);
return resultTypeInfo.clearType();
}
traceForResolveResult.record(isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression, functionResults.getResultingCall());
return JetTypeInfo.create(functionResults.getResultingDescriptor().getReturnType(), dataFlowInfo);
traceForResolveResult.record(isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression,
functionResults.getResultingCall());
return resultTypeInfo.replaceType(functionResults.getResultingDescriptor().getReturnType());
}
}
@@ -248,7 +248,7 @@ public class ControlStructureTypingUtils {
@NotNull
/*package*/ static TracingStrategy createTracingForSpecialConstruction(
final @NotNull Call call,
final @NotNull String constructionName,
@NotNull String constructionName,
final @NotNull ExpressionTypingContext context
) {
class CheckTypeContext {
@@ -22,11 +22,9 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.JetNodeTypes;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
@@ -43,6 +41,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import java.util.ArrayList;
import java.util.Collections;
@@ -104,15 +103,19 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
if (elseBranch == null) {
if (thenBranch != null) {
TypeInfoWithJumpInfo result = getTypeInfoWhenOnlyOneBranchIsPresent(
JetTypeInfo result = getTypeInfoWhenOnlyOneBranchIsPresent(
thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, ifExpression, isStatement);
// If jump was possible, take condition check info as the jump info
return result.getJumpOutPossible()
? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo)
: result;
}
return DataFlowUtils.checkImplicitCast(components.builtIns.getUnitType(), ifExpression, contextWithExpectedType,
isStatement, thenInfo.or(elseInfo));
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkImplicitCast(
components.builtIns.getUnitType(), ifExpression,
contextWithExpectedType, isStatement
),
thenInfo.or(elseInfo)
);
}
if (thenBranch == null) {
return getTypeInfoWhenOnlyOneBranchIsPresent(
@@ -130,8 +133,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
contextWithExpectedType, dataFlowInfoForArguments);
BindingContext bindingContext = context.trace.getBindingContext();
TypeInfoWithJumpInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext);
TypeInfoWithJumpInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext);
JetTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext);
JetTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext);
assert thenTypeInfo != null : "'Then' branch of if expression was not processed: " + ifExpression;
assert elseTypeInfo != null : "'Else' branch of if expression was not processed: " + ifExpression;
boolean loopBreakContinuePossible = thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible();
@@ -159,13 +162,14 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
}
JetType resultType = resolvedCall.getResultingDescriptor().getReturnType();
JetTypeInfo result = DataFlowUtils.checkImplicitCast(resultType, ifExpression, contextWithExpectedType, isStatement, resultDataFlowInfo);
// If break or continue was possible, take condition check info as the jump info
return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), loopBreakContinuePossible, conditionDataFlowInfo);
return TypeInfoFactoryPackage
.createTypeInfo(DataFlowUtils.checkImplicitCast(resultType, ifExpression, contextWithExpectedType, isStatement),
resultDataFlowInfo, loopBreakContinuePossible, conditionDataFlowInfo);
}
@NotNull
private TypeInfoWithJumpInfo getTypeInfoWhenOnlyOneBranchIsPresent(
private JetTypeInfo getTypeInfoWhenOnlyOneBranchIsPresent(
@NotNull JetExpression presentBranch,
@NotNull WritableScopeImpl presentScope,
@NotNull DataFlowInfo presentInfo,
@@ -176,7 +180,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
) {
ExpressionTypingContext newContext = context.replaceDataFlowInfo(presentInfo).replaceExpectedType(NO_EXPECTED_TYPE)
.replaceContextDependency(INDEPENDENT);
TypeInfoWithJumpInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
JetTypeInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
presentScope, Collections.singletonList(presentBranch), CoercionStrategy.NO_COERCION, newContext);
JetType type = typeInfo.getType();
DataFlowInfo dataFlowInfo;
@@ -185,9 +189,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
} else {
dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo);
}
JetType typeForIfExpression = DataFlowUtils.checkType(components.builtIns.getUnitType(), ifExpression, context);
JetTypeInfo result = DataFlowUtils.checkImplicitCast(typeForIfExpression, ifExpression, context, isStatement, dataFlowInfo);
return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), typeInfo.getJumpOutPossible(), typeInfo.getJumpFlowInfo());
return typeInfo.replaceType(components.builtIns.getUnitType()).checkType(ifExpression, context).
checkImplicitCast(ifExpression, context, isStatement).replaceDataFlowInfo(dataFlowInfo);
}
@Override
@@ -211,13 +214,15 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
DataFlowInfo dataFlowInfo = checkCondition(context.scope, condition, context);
JetExpression body = expression.getBody();
TypeInfoWithJumpInfo bodyTypeInfo = null;
JetTypeInfo bodyTypeInfo;
DataFlowInfo conditionInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, context).and(dataFlowInfo);
if (body != null) {
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in while's condition");
DataFlowInfo conditionInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, context).and(dataFlowInfo);
bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
scopeToExtend, Collections.singletonList(body),
CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(conditionInfo));
} else {
bodyTypeInfo = TypeInfoFactoryPackage.createTypeInfo(conditionInfo);
}
// Condition is false at this point only if there is no jumps outside
@@ -229,12 +234,13 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// In this case we must record data flow information at the nearest break / continue and
// .and it with entrance data flow information, because while body until break is executed at least once in this case
// See KT-6284
if (bodyTypeInfo != null && JetPsiUtil.isTrueConstant(condition)) {
if (body != null && JetPsiUtil.isTrueConstant(condition)) {
// We should take data flow info from the first jump point,
// but without affecting changing variables
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo()));
}
return DataFlowUtils.checkType(components.builtIns.getUnitType(), expression, contextWithExpectedType, dataFlowInfo);
return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo(
dataFlowInfo);
}
private boolean containsJumpOutOfLoop(final JetLoopExpression loopExpression, final ExpressionTypingContext context) {
@@ -296,7 +302,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// Here we must record data flow information at the end of the body (or at the first jump, to be precise) and
// .and it with entrance data flow information, because do-while body is executed at least once
// See KT-6283
TypeInfoWithJumpInfo bodyTypeInfo = null;
JetTypeInfo bodyTypeInfo;
if (body instanceof JetFunctionLiteralExpression) {
JetFunctionLiteralExpression function = (JetFunctionLiteralExpression) body;
JetFunctionLiteral functionLiteral = function.getFunctionLiteral();
@@ -308,7 +314,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
context.trace.record(BindingContext.BLOCK, function);
}
else {
facade.getTypeInfo(body, context.replaceScope(context.scope));
bodyTypeInfo = facade.getTypeInfo(body, context.replaceScope(context.scope));
}
}
else if (body != null) {
@@ -324,6 +330,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
writableScope, block, CoercionStrategy.NO_COERCION, context);
}
else {
bodyTypeInfo = TypeInfoFactoryPackage.createTypeInfo(context);
}
JetExpression condition = expression.getCondition();
DataFlowInfo conditionDataFlowInfo = checkCondition(conditionScope, condition, context);
DataFlowInfo dataFlowInfo;
@@ -337,12 +346,13 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// Here we must record data flow information at the end of the body (or at the first jump, to be precise) and
// .and it with entrance data flow information, because do-while body is executed at least once
// See KT-6283
if (bodyTypeInfo != null) {
if (body != null) {
// We should take data flow info from the first jump point,
// but without affecting changing variables
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo()));
}
return DataFlowUtils.checkType(components.builtIns.getUnitType(), expression, contextWithExpectedType, dataFlowInfo);
return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo(
dataFlowInfo);
}
@Override
@@ -361,14 +371,17 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetExpression loopRange = expression.getLoopRange();
JetType expectedParameterType = null;
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
JetTypeInfo loopRangeInfo;
if (loopRange != null) {
ExpressionReceiver loopRangeReceiver = getExpressionReceiver(facade, loopRange, context.replaceScope(context.scope));
dataFlowInfo = facade.getTypeInfo(loopRange, context).getDataFlowInfo();
loopRangeInfo = facade.getTypeInfo(loopRange, context);
if (loopRangeReceiver != null) {
expectedParameterType = components.forLoopConventionsChecker.checkIterableConvention(loopRangeReceiver, context);
}
}
else {
loopRangeInfo = TypeInfoFactoryPackage.createTypeInfo(context);
}
WritableScope loopScope = newWritableScopeImpl(context, "Scope with for-loop index");
@@ -389,12 +402,17 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
}
JetExpression body = expression.getBody();
JetTypeInfo bodyTypeInfo;
if (body != null) {
components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(loopScope, Collections.singletonList(body),
CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(dataFlowInfo));
bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(loopScope, Collections.singletonList(body),
CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo()));
}
else {
bodyTypeInfo = loopRangeInfo;
}
return DataFlowUtils.checkType(components.builtIns.getUnitType(), expression, contextWithExpectedType, dataFlowInfo);
return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo(
loopRangeInfo.getDataFlowInfo());
}
private VariableDescriptor createLoopParameterDescriptor(
@@ -462,10 +480,10 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
}
}
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
JetTypeInfo result = TypeInfoFactoryPackage.createTypeInfo(context);
if (finallyBlock != null) {
dataFlowInfo = facade.getTypeInfo(finallyBlock.getFinalExpression(),
context.replaceExpectedType(NO_EXPECTED_TYPE)).getDataFlowInfo();
result = facade.getTypeInfo(finallyBlock.getFinalExpression(),
context.replaceExpectedType(NO_EXPECTED_TYPE));
}
JetType type = facade.getTypeInfo(tryBlock, context).getType();
@@ -473,10 +491,10 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
types.add(type);
}
if (types.isEmpty()) {
return JetTypeInfo.create(null, dataFlowInfo);
return result.clearType();
}
else {
return JetTypeInfo.create(CommonSupertypes.commonSupertype(types), dataFlowInfo);
return result.replaceType(CommonSupertypes.commonSupertype(types));
}
}
@@ -488,7 +506,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
facade.getTypeInfo(thrownExpression, context
.replaceExpectedType(throwableType).replaceScope(context.scope).replaceContextDependency(INDEPENDENT));
}
return DataFlowUtils.checkType(components.builtIns.getNothingType(), expression, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression);
}
@Override
@@ -556,7 +574,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(RETURN_TYPE_MISMATCH.on(expression, expectedType));
}
}
return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createCheckedTypeInfo(resultType, context, expression);
}
private static boolean isClassInitializer(@NotNull Pair<FunctionDescriptor, PsiElement> containingFunInfo) {
@@ -565,17 +583,17 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
}
@Override
public TypeInfoWithJumpInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext context) {
public JetTypeInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext context) {
LabelResolver.INSTANCE.resolveControlLabel(expression, context);
JetTypeInfo result = DataFlowUtils.checkType(components.builtIns.getNothingType(), expression, context, context.dataFlowInfo);
return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), true, result.getDataFlowInfo());
return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression).
replaceJumpOutPossible(true);
}
@Override
public TypeInfoWithJumpInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext context) {
public JetTypeInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext context) {
LabelResolver.INSTANCE.resolveControlLabel(expression, context);
JetTypeInfo result = DataFlowUtils.checkType(components.builtIns.getNothingType(), expression, context, context.dataFlowInfo);
return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), true, result.getDataFlowInfo());
return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression).
replaceJumpOutPossible(true);
}
@NotNull
@@ -37,10 +37,10 @@ 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.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 org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import java.util.Collection;
@@ -92,9 +92,9 @@ public class DataFlowUtils {
JetExpression right = expression.getRight();
if (right == null) return;
JetType lhsType = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, left);
JetType lhsType = context.trace.getBindingContext().getType(left);
if (lhsType == null) return;
JetType rhsType = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, right);
JetType rhsType = context.trace.getBindingContext().getType(right);
if (rhsType == null) return;
DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, lhsType, context);
@@ -144,23 +144,9 @@ public class DataFlowUtils {
return context.dataFlowInfo.and(result.get());
}
@NotNull
public static JetTypeInfo checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context, @NotNull DataFlowInfo dataFlowInfo) {
return JetTypeInfo.create(checkType(expressionType, expression, context), dataFlowInfo);
}
@NotNull
public static JetTypeInfo checkType(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context) {
JetType type = checkType(typeInfo.getType(), expression, context);
if (type == typeInfo.getType()) {
return typeInfo;
}
return JetTypeInfo.create(type, typeInfo.getDataFlowInfo());
}
@Nullable
public static JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context) {
return checkType(expressionType, expression, context, (Ref<Boolean>) null);
return checkType(expressionType, expression, context, null);
}
@Nullable
@@ -215,11 +201,6 @@ public class DataFlowUtils {
}
}
@NotNull
public static JetTypeInfo checkStatementType(@NotNull JetExpression expression, @NotNull ResolutionContext context, @NotNull DataFlowInfo dataFlowInfo) {
return JetTypeInfo.create(checkStatementType(expression, context), dataFlowInfo);
}
@Nullable
public static JetType checkStatementType(@NotNull JetExpression expression, @NotNull ResolutionContext context) {
if (!noExpectedType(context.expectedType) && !KotlinBuiltIns.isUnit(context.expectedType) && !context.expectedType.isError()) {
@@ -229,13 +210,8 @@ public class DataFlowUtils {
return KotlinBuiltIns.getInstance().getUnitType();
}
@NotNull
public static JetTypeInfo checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context, boolean isStatement, DataFlowInfo dataFlowInfo) {
return JetTypeInfo.create(checkImplicitCast(expressionType, expression, context, isStatement), dataFlowInfo);
}
@Nullable
public static JetType checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context, boolean isStatement) {
public static JetType checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context, boolean isStatement) {
if (expressionType != null && context.expectedType == NO_EXPECTED_TYPE && context.contextDependency == INDEPENDENT && !isStatement
&& (KotlinBuiltIns.isUnit(expressionType) || KotlinBuiltIns.isAnyOrNullableAny(expressionType))
&& !TypesPackage.isDynamic(expressionType)) {
@@ -249,7 +225,7 @@ public class DataFlowUtils {
facade.checkStatementType(
expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
context.trace.report(EXPRESSION_EXPECTED.on(expression, expression));
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
@NotNull
@@ -17,9 +17,7 @@
package org.jetbrains.kotlin.types.expressions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.types.JetTypeInfo;
public interface ExpressionTypingFacade {
@NotNull
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.types.expressions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.types.JetTypeInfo;
/*package*/ interface ExpressionTypingInternals extends ExpressionTypingFacade {
@NotNull
@@ -44,7 +44,7 @@ import org.jetbrains.kotlin.resolve.scopes.WritableScope;
import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl;
import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.JetTypeInfo;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import javax.inject.Inject;
import java.util.Iterator;
@@ -262,7 +262,7 @@ public class ExpressionTypingServices {
JetTypeInfo r;
if (block.isEmpty()) {
r = DataFlowUtils.checkType(builtIns.getUnitType(), expression, context, context.dataFlowInfo);
r = TypeInfoFactoryPackage.createCheckedTypeInfo(builtIns.getUnitType(), context, expression);
}
else {
r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression,
@@ -308,20 +308,20 @@ public class ExpressionTypingServices {
* Determines block returned type and data flow information at the end of the block AND
* at the nearest jump point from the block beginning.
*/
/*package*/ TypeInfoWithJumpInfo getBlockReturnedTypeWithWritableScope(
/*package*/ JetTypeInfo getBlockReturnedTypeWithWritableScope(
@NotNull WritableScope scope,
@NotNull List<? extends JetElement> block,
@NotNull CoercionStrategy coercionStrategyForLastExpression,
@NotNull ExpressionTypingContext context
) {
if (block.isEmpty()) {
return new TypeInfoWithJumpInfo(builtIns.getUnitType(), context.dataFlowInfo, false, context.dataFlowInfo);
return new JetTypeInfo(builtIns.getUnitType(), context.dataFlowInfo, false, context.dataFlowInfo);
}
ExpressionTypingInternals blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(expressionTypingComponents, scope);
ExpressionTypingContext newContext = context.replaceScope(scope).replaceExpectedType(NO_EXPECTED_TYPE);
JetTypeInfo result = JetTypeInfo.create(null, context.dataFlowInfo);
JetTypeInfo result = TypeInfoFactoryPackage.createTypeInfo(context);
// Jump point data flow info
DataFlowInfo beforeJumpInfo = newContext.dataFlowInfo;
boolean jumpOutPossible = false;
@@ -344,14 +344,8 @@ public class ExpressionTypingServices {
DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
// If jump is not possible, we take new data flow info before jump
if (!jumpOutPossible) {
if (result instanceof TypeInfoWithJumpInfo) {
TypeInfoWithJumpInfo jumpTypeInfo = (TypeInfoWithJumpInfo) result;
beforeJumpInfo = jumpTypeInfo.getJumpFlowInfo();
jumpOutPossible = jumpTypeInfo.getJumpOutPossible();
}
else {
beforeJumpInfo = newDataFlowInfo;
}
beforeJumpInfo = result.getJumpFlowInfo();
jumpOutPossible = result.getJumpOutPossible();
}
if (newDataFlowInfo != context.dataFlowInfo) {
newContext = newContext.replaceDataFlowInfo(newDataFlowInfo);
@@ -359,7 +353,7 @@ public class ExpressionTypingServices {
}
blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(expressionTypingComponents, scope);
}
return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), jumpOutPossible, beforeJumpInfo);
return result.replaceJumpOutPossible(jumpOutPossible).replaceJumpFlowInfo(beforeJumpInfo);
}
private JetTypeInfo getTypeOfLastExpressionInBlock(
@@ -397,7 +391,7 @@ public class ExpressionTypingServices {
if (mightBeUnit) {
// ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments
assert result.getType() == null || KotlinBuiltIns.isUnit(result.getType());
result = JetTypeInfo.create(builtIns.getUnitType(), context.dataFlowInfo);
result = result.replaceType(builtIns.getUnitType()).replaceDataFlowInfo(context.dataFlowInfo);
}
}
return result;
@@ -45,9 +45,9 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.JetTypeInfo;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.ArrayList;
@@ -192,7 +192,7 @@ public class ExpressionTypingUtils {
@NotNull JetType argumentType
) {
JetExpression fakeExpression = JetPsiFactory(project).createExpression(argumentName);
trace.record(EXPRESSION_TYPE, fakeExpression, argumentType);
trace.recordType(fakeExpression, argumentType);
trace.record(PROCESSED, fakeExpression);
return fakeExpression;
}
@@ -336,7 +336,7 @@ public class ExpressionTypingUtils {
) {
return expression != null
? facade.getTypeInfo(expression, context)
: JetTypeInfo.create(null, context.dataFlowInfo);
: TypeInfoFactoryPackage.createTypeInfo(context);
}
@SuppressWarnings("SuspiciousMethodCalls")
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.types.expressions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.psi.JetVisitor;
import org.jetbrains.kotlin.types.JetTypeInfo;
/*package*/ abstract class ExpressionTypingVisitor extends JetVisitor<JetTypeInfo, ExpressionTypingContext> {
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.WritableScope;
import org.jetbrains.kotlin.types.DeferredType;
import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.JetTypeInfo;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException;
import org.jetbrains.kotlin.utils.KotlinFrontEndException;
@@ -99,7 +99,8 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
if (typeInfo.getType() != null) {
return typeInfo;
}
return JetTypeInfo.create(ErrorUtils.createErrorType("Type for " + expression.getText()), context.dataFlowInfo);
return typeInfo.replaceType(ErrorUtils.createErrorType("Type for " + expression.getText())).replaceDataFlowInfo(
context.dataFlowInfo);
}
@Override
@@ -130,7 +131,7 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
}
@NotNull
private JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
static private JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
try {
JetTypeInfo recordedTypeInfo = BindingContextUtils.getRecordedTypeInfo(expression, context.trace.getBindingContext());
if (recordedTypeInfo != null) {
@@ -140,34 +141,19 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
try {
result = expression.accept(visitor, context);
// Some recursive definitions (object expressions) must put their types in the cache manually:
if (context.trace.get(BindingContext.PROCESSED, expression)) {
JetType type = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
if (result instanceof TypeInfoWithJumpInfo) {
TypeInfoWithJumpInfo jumpTypeInfo = (TypeInfoWithJumpInfo) result;
return jumpTypeInfo.replaceType(type);
}
else {
return JetTypeInfo.create(type, result.getDataFlowInfo());
}
if (Boolean.TRUE.equals(context.trace.get(BindingContext.PROCESSED, expression))) {
JetType type = context.trace.getBindingContext().getType(expression);
return result.replaceType(type);
}
if (result.getType() instanceof DeferredType) {
result = JetTypeInfo.create(((DeferredType) result.getType()).getDelegate(), result.getDataFlowInfo());
result = result.replaceType(((DeferredType) result.getType()).getDelegate());
}
if (result.getType() != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, expression, result.getType());
}
if (result instanceof TypeInfoWithJumpInfo) {
TypeInfoWithJumpInfo jumpTypeInfo = (TypeInfoWithJumpInfo)result;
if (jumpTypeInfo.getJumpOutPossible()) {
context.trace.record(BindingContext.EXPRESSION_JUMP_OUT_POSSIBLE, expression, true);
}
}
context.trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, result);
}
catch (ReenteringLazyValueComputationException e) {
context.trace.report(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM.on(expression));
result = JetTypeInfo.create(null, context.dataFlowInfo);
result = TypeInfoFactoryPackage.createTypeInfo(context);
}
context.trace.record(BindingContext.PROCESSED, expression);
@@ -183,10 +169,10 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
catch (Throwable e) {
context.trace.report(Errors.EXCEPTION_FROM_ANALYZER.on(expression, e));
logOrThrowException(expression, e);
return JetTypeInfo.create(
ErrorUtils.createErrorType(e.getClass().getSimpleName() + " from analyzer"),
context.dataFlowInfo
);
return TypeInfoFactoryPackage.createTypeInfo(
ErrorUtils.createErrorType(e.getClass().getSimpleName() + " from analyzer"),
context
);
}
}
@@ -43,9 +43,9 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.scopes.WritableScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.JetTypeInfo;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import java.util.Collection;
@@ -101,7 +101,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), declaration,
components.additionalCheckerProvider,
components.dynamicTypesSettings);
return DataFlowUtils.checkStatementType(declaration, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(declaration, context), context);
}
@Override
@@ -135,11 +135,11 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
VariableDescriptor propertyDescriptor = components.expressionTypingServices.getDescriptorResolver().
resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace);
JetExpression initializer = property.getInitializer();
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
JetTypeInfo typeInfo;
if (initializer != null) {
JetType outType = propertyDescriptor.getType();
JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
dataFlowInfo = typeInfo.getDataFlowInfo();
typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
JetType type = typeInfo.getType();
// At this moment we do not take initializer value into account if type is given for a property
// We can comment first part of this condition to take them into account, like here: var s: String? = "xyz"
@@ -151,9 +151,12 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
DataFlowValue initializerDataFlowValue = DataFlowValueFactory.createDataFlowValue(initializer, type, context);
// We cannot say here anything new about initializerDataFlowValue
// except it has the same value as variableDataFlowValue
dataFlowInfo = dataFlowInfo.assign(variableDataFlowValue, initializerDataFlowValue);
typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.assign(variableDataFlowValue, initializerDataFlowValue));
}
}
else {
typeInfo = TypeInfoFactoryPackage.createTypeInfo(context);
}
{
VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName());
@@ -162,7 +165,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
scope.addVariableDescriptor(propertyDescriptor);
ModifiersChecker.create(context.trace, components.additionalCheckerProvider).checkModifiersForLocalDeclaration(property, propertyDescriptor);
return DataFlowUtils.checkStatementType(property, context, dataFlowInfo);
return typeInfo.replaceType(DataFlowUtils.checkStatementType(property, context));
}
@Override
@@ -173,16 +176,16 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
JetExpression initializer = multiDeclaration.getInitializer();
if (initializer == null) {
context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration));
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
ExpressionReceiver expressionReceiver = ExpressionTypingUtils.getExpressionReceiver(
facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
DataFlowInfo dataFlowInfo = facade.getTypeInfo(initializer, context).getDataFlowInfo();
JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context);
if (expressionReceiver == null) {
return JetTypeInfo.create(null, dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
components.expressionTypingUtils.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
return DataFlowUtils.checkStatementType(multiDeclaration, context, dataFlowInfo);
return typeInfo.replaceType(DataFlowUtils.checkStatementType(multiDeclaration, context));
}
@Override
@@ -197,7 +200,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), klass,
components.additionalCheckerProvider,
components.dynamicTypesSettings);
return DataFlowUtils.checkStatementType(klass, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(klass, context), context);
}
@Override
@@ -208,7 +211,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
@Override
public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) {
return DataFlowUtils.checkStatementType(dcl, context, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(dcl, context), context);
}
@Override
@@ -225,7 +228,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
else {
return facade.getTypeInfo(expression, context);
}
return DataFlowUtils.checkType(result.getType(), expression, context, result.getDataFlowInfo());
return result.checkType(expression, context);
}
@NotNull
@@ -241,20 +244,19 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
JetExpression leftOperand = expression.getLeft();
JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
JetType leftType = leftInfo.getType();
DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
JetExpression right = expression.getRight();
JetExpression left = leftOperand == null ? null : JetPsiUtil.deparenthesize(leftOperand);
if (right == null || left == null) {
temporary.commit();
return JetTypeInfo.create(null, dataFlowInfo);
return leftInfo.clearType();
}
if (leftType == null) {
dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
temporary.commit();
return JetTypeInfo.create(null, dataFlowInfo);
return rightInfo.clearType();
}
ExpressionReceiver receiver = new ExpressionReceiver(left, leftType);
@@ -292,6 +294,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
}
JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
JetTypeInfo rightInfo = leftInfo;
if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess()) {
// Both 'plus()' and 'plusAssign()' available => ambiguity
OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
@@ -300,7 +303,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
descriptors.add(resolvedCall.getResultingDescriptor());
}
dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
}
else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
@@ -319,12 +322,12 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
context.trace, "trace to resolve array set method for assignment", expression));
basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace);
}
dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
DataFlowUtils.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(dataFlowInfo));
rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
DataFlowUtils.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(rightInfo.getDataFlowInfo()));
basic.checkLValue(context.trace, context, leftOperand, right);
}
temporary.commit();
return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo);
return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
}
@NotNull
@@ -336,30 +339,33 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
JetExpression right = expression.getRight();
if (left instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo);
if (right == null) return TypeInfoFactoryPackage.createTypeInfo(context);
JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
basic.checkLValue(context.trace, context, arrayAccessExpression, right);
return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType),
typeInfo.getDataFlowInfo());
return typeInfo.replaceType(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType));
}
JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
JetType leftType = leftInfo.getType();
DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
JetTypeInfo rightInfo;
if (right != null) {
JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
dataFlowInfo = rightInfo.getDataFlowInfo();
JetType rightType = rightInfo.getType();
if (left != null && leftType != null && rightType != null) {
DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, leftType, context);
DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context);
// We cannot say here anything new about rightValue except it has the same value as leftValue
dataFlowInfo = dataFlowInfo.assign(leftValue, rightValue);
rightInfo = rightInfo.replaceDataFlowInfo(dataFlowInfo.assign(leftValue, rightValue));
}
}
else {
rightInfo = leftInfo;
}
if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
basic.checkLValue(context.trace, context, leftOperand, right);
}
return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo);
return rightInfo.replaceType(DataFlowUtils.checkStatementType(expression, contextWithExpectedType));
}
@@ -371,7 +377,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
@Override
public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext context) {
context.trace.report(UNSUPPORTED.on(element, "in a block"));
return JetTypeInfo.create(null, context.dataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(context);
}
@Override
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.BindingContext.AUTO_CREATED_IT
import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE
import org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.scopes.WritableScope
import org.jetbrains.kotlin.resolve.source.toSourceElement
@@ -41,6 +40,8 @@ import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createCheckedTypeInfo
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
import org.jetbrains.kotlin.utils.addIfNotNull
public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) {
@@ -99,10 +100,10 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
}
if (isStatement) {
return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo)
return createTypeInfo(DataFlowUtils.checkStatementType(function, context), context)
}
else {
return DataFlowUtils.checkType(createFunctionType(functionDescriptor), function, context, context.dataFlowInfo)
return createCheckedTypeInfo(createFunctionType(functionDescriptor), context, function)
}
}
@@ -138,10 +139,10 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
val resultType = createFunctionType(functionDescriptor)!!
if (functionTypeExpected) {
// all checks were done before
return JetTypeInfo.create(resultType, context.dataFlowInfo)
return createTypeInfo(resultType, context)
}
return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo)
return createCheckedTypeInfo(resultType, context, expression)
}
private fun createFunctionDescriptor(
@@ -197,7 +198,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
// This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions
context.trace.record(EXPECTED_RETURN_TYPE, functionLiteral, expectedType)
val typeOfBodyExpression = // Type-check the body
components.expressionTypingServices.getBlockReturnedType(functionLiteral.getBodyExpression(), COERCION_TO_UNIT, newContext).getType()
components.expressionTypingServices.getBlockReturnedType(functionLiteral.getBodyExpression(), COERCION_TO_UNIT, newContext).type
return declaredReturnType ?: computeReturnTypeBasedOnReturnExpressions(functionLiteral, context, typeOfBodyExpression)
}
@@ -218,7 +219,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
}
else {
// the type should have been computed by getBlockReturnedType() above, but can be null, if returnExpression contains some error
returnedExpressionTypes.addIfNotNull(context.trace.get<JetExpression, JetType>(EXPRESSION_TYPE, returnedExpression))
returnedExpressionTypes.addIfNotNull(context.trace.getType(returnedExpression))
}
}
@@ -226,7 +227,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
for (returnExpression in returnExpressions) {
val returnedExpression = returnExpression.getReturnedExpression()
if (returnedExpression != null) {
val type = context.trace.get<JetExpression, JetType>(EXPRESSION_TYPE, returnedExpression)
val type = context.trace.getType(returnedExpression)
if (type == null || !KotlinBuiltIns.isUnit(type)) {
context.trace.report(RETURN_TYPE_MISMATCH.on(returnedExpression, components.builtIns.getUnitType()))
}
@@ -0,0 +1,66 @@
/*
* 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.types.expressions
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.types.JetType
/**
* Stores simultaneously type of current expression together with data flow info
* and jump point data flow info, together with information about possible jump outside. For example:
* do {
* x!!.foo()
* if (bar()) break;
* y!!.gav()
* } while (bis())
* At the end current data flow info is x != null && y != null, but jump data flow info is x != null only.
* Both break and continue are counted as possible jump outside of a loop, but return is not.
*/
/*package*/ open class JetTypeInfo(
val type: JetType?,
val dataFlowInfo: DataFlowInfo,
val jumpOutPossible: Boolean = false,
val jumpFlowInfo: DataFlowInfo = dataFlowInfo
) {
fun clearType() = replaceType(null)
fun checkType(expression: JetExpression, context: ResolutionContext<*>) =
replaceType(DataFlowUtils.checkType(type, expression, context))
fun checkImplicitCast(expression: JetExpression, context: ResolutionContext<*>, isStatement: Boolean) =
replaceType(DataFlowUtils.checkImplicitCast(type, expression, context, isStatement))
// NB: do not compare type with this.type because this comparison is complex and unstabld
fun replaceType(type: JetType?) = JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo)
fun replaceJumpOutPossible(jumpOutPossible: Boolean) =
if (jumpOutPossible == this.jumpOutPossible) this else JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo)
fun replaceJumpFlowInfo(jumpFlowInfo: DataFlowInfo) =
if (jumpFlowInfo == this.jumpFlowInfo) this else JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo)
fun replaceDataFlowInfo(dataFlowInfo: DataFlowInfo) =
if (dataFlowInfo == this.dataFlowInfo) this
// If jump flow information was the same, it should be changed together
else if (this.dataFlowInfo == jumpFlowInfo) JetTypeInfo(type, dataFlowInfo, jumpOutPossible, dataFlowInfo)
// Otherwise they are changed separately
else JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo)
}
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.scopes.WritableScope;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import java.util.Collections;
import java.util.Set;
@@ -50,18 +51,18 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetTypeInfo visitIsExpression(@NotNull JetIsExpression expression, ExpressionTypingContext contextWithExpectedType) {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(
INDEPENDENT);
JetExpression leftHandSide = expression.getLeftHandSide();
JetTypeInfo typeInfo = facade.safeGetTypeInfo(leftHandSide, context.replaceScope(context.scope));
JetType knownType = typeInfo.getType();
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
if (expression.getTypeReference() != null) {
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(leftHandSide, knownType, context);
DataFlowInfo conditionInfo = checkTypeForIs(context, knownType, expression.getTypeReference(), dataFlowValue).thenInfo;
DataFlowInfo newDataFlowInfo = conditionInfo.and(dataFlowInfo);
DataFlowInfo newDataFlowInfo = conditionInfo.and(typeInfo.getDataFlowInfo());
context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo);
}
return DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getBooleanType(), expression, contextWithExpectedType, dataFlowInfo);
return typeInfo.replaceType(KotlinBuiltIns.getInstance().getBooleanType()).checkType(expression, contextWithExpectedType);
}
@Override
@@ -77,11 +78,13 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
JetExpression subjectExpression = expression.getSubjectExpression();
JetType subjectType;
boolean loopBreakContinuePossible = false;
if (subjectExpression == null) {
subjectType = ErrorUtils.createErrorType("Unknown type");
}
else {
JetTypeInfo typeInfo = facade.safeGetTypeInfo(subjectExpression, context);
loopBreakContinuePossible = typeInfo.getJumpOutPossible();
subjectType = typeInfo.getType();
context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo());
}
@@ -107,6 +110,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION;
JetTypeInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
scopeToExtend, Collections.singletonList(bodyExpression), coercionStrategy, newContext);
loopBreakContinuePossible |= typeInfo.getJumpOutPossible();
JetType type = typeInfo.getType();
if (type != null) {
expressionTypes.add(type);
@@ -124,10 +128,12 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
commonDataFlowInfo = context.dataFlowInfo;
}
if (!expressionTypes.isEmpty()) {
return DataFlowUtils.checkImplicitCast(CommonSupertypes.commonSupertype(expressionTypes), expression, contextWithExpectedType, isStatement, commonDataFlowInfo);
}
return JetTypeInfo.create(null, commonDataFlowInfo);
return TypeInfoFactoryPackage.createTypeInfo(expressionTypes.isEmpty() ? null : DataFlowUtils.checkImplicitCast(
CommonSupertypes.commonSupertype(expressionTypes), expression,
contextWithExpectedType, isStatement),
commonDataFlowInfo,
loopBreakContinuePossible,
contextWithExpectedType.dataFlowInfo);
}
@NotNull
@@ -0,0 +1,43 @@
/*
* 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.types.expressions.typeInfoFactory
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.expressions.JetTypeInfo
/**
* Functions in this file are intended to create type info instances in different circumstances
*/
public fun createTypeInfo(type: JetType?): JetTypeInfo = createTypeInfo(type, DataFlowInfo.EMPTY)
public fun createTypeInfo(dataFlowInfo: DataFlowInfo): JetTypeInfo = JetTypeInfo(null, dataFlowInfo)
public fun createTypeInfo(context: ResolutionContext<*>): JetTypeInfo = createTypeInfo(context.dataFlowInfo)
public fun createTypeInfo(type: JetType?, dataFlowInfo: DataFlowInfo): JetTypeInfo = JetTypeInfo(type, dataFlowInfo)
public fun createTypeInfo(type: JetType?, context: ResolutionContext<*>): JetTypeInfo = createTypeInfo(type, context.dataFlowInfo)
public fun createTypeInfo(type: JetType?, dataFlowInfo: DataFlowInfo, jumpPossible: Boolean, jumpFlowInfo: DataFlowInfo): JetTypeInfo =
JetTypeInfo(type, dataFlowInfo, jumpPossible, jumpFlowInfo)
public fun createCheckedTypeInfo(type: JetType?, context: ResolutionContext<*>, expression: JetExpression): JetTypeInfo =
createTypeInfo(type, context).checkType(expression, context)
@@ -1,46 +0,0 @@
/*
* 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.types.expressions
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.JetTypeInfo
/**
* A local descendant of JetTypeInfo. Stores simultaneously current type with data flow info
* and jump point data flow info, together with information about possible jump outside. For example:
* do {
* x!!.foo()
* if (bar()) break;
* y!!.gav()
* } while (bis())
* At the end current data flow info is x != null && y != null, but jump data flow info is x != null only.
* Both break and continue are counted as possible jump outside of a loop, but return is not.
*/
/*package*/ class TypeInfoWithJumpInfo(
type: JetType?,
dataFlowInfo: DataFlowInfo,
val jumpOutPossible: Boolean = false,
val jumpFlowInfo: DataFlowInfo = dataFlowInfo
) : JetTypeInfo(type, dataFlowInfo) {
fun replaceType(type: JetType?) = TypeInfoWithJumpInfo(type, getDataFlowInfo(), jumpOutPossible, jumpFlowInfo)
fun replaceJumpOutPossible(jumpOutPossible: Boolean) = TypeInfoWithJumpInfo(getType(), getDataFlowInfo(), jumpOutPossible, jumpFlowInfo)
fun replaceJumpFlowInfo(jumpFlowInfo: DataFlowInfo) = TypeInfoWithJumpInfo(getType(), getDataFlowInfo(), jumpOutPossible, jumpFlowInfo)
}
@@ -0,0 +1,11 @@
public fun foo(x: String?, y: String?): Int {
while (true) {
val z = x ?: if (y == null) break else <!DEBUG_INFO_SMARTCAST!>y<!>
// z is not null in both branches
z.length()
// y is not null in both branches
<!DEBUG_INFO_SMARTCAST!>y<!>.length()
}
// y is null because of the break
return y<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,3 @@
package
public fun foo(/*0*/ x: kotlin.String?, /*1*/ y: kotlin.String?): kotlin.Int
@@ -0,0 +1,15 @@
public fun foo(x: String?): Int {
var y: Any
@loop while (true) {
y = when (x) {
null -> break@loop
"abc" -> return 0
"xyz" -> return 1
else -> <!DEBUG_INFO_SMARTCAST!>x<!>.length()
}
// y is always Int after when
<!DEBUG_INFO_SMARTCAST!>y<!>: Int
}
// x is null because of the break
return x<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,3 @@
package
public fun foo(/*0*/ x: kotlin.String?): kotlin.Int
@@ -0,0 +1,12 @@
fun bar(): Boolean { return true }
public fun foo(x: String?): Int {
var y: Any
do {
y = ""
y = if (x == null) break else <!DEBUG_INFO_SMARTCAST!>x<!>
} while (bar())
y.hashCode()
// x is null because of the break
return x<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,4 @@
package
internal fun bar(): kotlin.Boolean
public fun foo(/*0*/ x: kotlin.String?): kotlin.Int
@@ -0,0 +1,10 @@
public fun foo(x: String?): Int {
var y: Any
while (true) {
y = if (x == null) break else <!DEBUG_INFO_SMARTCAST!>x<!>
}
// In future we can infer this initialization
<!UNINITIALIZED_VARIABLE!>y<!>.hashCode()
// x is null because of the break
return x<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,3 @@
package
public fun foo(/*0*/ x: kotlin.String?): kotlin.Int
@@ -0,0 +1,10 @@
public fun foo(x: String?): Int {
while (true) {
// After the check, smart cast should work
val y = if (x == null) break else <!DEBUG_INFO_SMARTCAST!>x<!>
// y is not null in both branches
y.length()
}
// x is null because of the break
return x<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,3 @@
package
public fun foo(/*0*/ x: kotlin.String?): kotlin.Int
@@ -0,0 +1,11 @@
public fun foo(x: String?, y: String?): Int {
while (true) {
val z = (if (y == null) break else x) ?: <!DEBUG_INFO_SMARTCAST!>y<!>
// z is not null in both branches
z.length()
// y is not null in both branches
<!DEBUG_INFO_SMARTCAST!>y<!>.length()
}
// y is null because of the break
return y<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,3 @@
package
public fun foo(/*0*/ x: kotlin.String?, /*1*/ y: kotlin.String?): kotlin.Int
@@ -0,0 +1,20 @@
fun bar(): Boolean { return true }
public fun foo(x: String?): Int {
var y: Int?
y = 0
@loop do {
<!DEBUG_INFO_SMARTCAST!>y<!> += when (x) {
null -> break@loop
"abc" -> return 0
"xyz" -> return 1
else -> <!DEBUG_INFO_SMARTCAST!>x<!>.length()
}
// y is always Int after when
<!DEBUG_INFO_SMARTCAST!>y<!>: Int
} while (bar())
// y is always Int even here
<!DEBUG_INFO_SMARTCAST!>y<!>: Int
// x is null because of the break
return x<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,4 @@
package
internal fun bar(): kotlin.Boolean
public fun foo(/*0*/ x: kotlin.String?): kotlin.Int
@@ -0,0 +1,12 @@
public fun foo(x: String?): Int {
@loop while (true) {
when (x) {
null -> break@loop
"abc" -> return 0
"xyz" -> return 1
else -> <!DEBUG_INFO_SMARTCAST!>x<!>.length()
}
}
// x is null because of the break
return x<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,3 @@
package
public fun foo(/*0*/ x: kotlin.String?): kotlin.Int
@@ -0,0 +1,13 @@
public fun foo(x: String?): Int {
@loop while (true) {
when (x) {
null -> return -1
"abc" -> return 0
"xyz" -> return 1
else -> break@loop
}
}
// x is not null because of the break
// but we are not able to detect it
return x<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,3 @@
package
public fun foo(/*0*/ x: kotlin.String?): kotlin.Int
@@ -11078,6 +11078,18 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/smartCasts/loops"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("assignElvisIfBreakInsideWhileTrue.kt")
public void testAssignElvisIfBreakInsideWhileTrue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.kt");
doTest(fileName);
}
@TestMetadata("assignWhenInsideWhileTrue.kt")
public void testAssignWhenInsideWhileTrue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.kt");
doTest(fileName);
}
@TestMetadata("doWhile.kt")
public void testDoWhile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/doWhile.kt");
@@ -11174,6 +11186,24 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("ifBreakAssignInsideDoWhile.kt")
public void testIfBreakAssignInsideDoWhile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt");
doTest(fileName);
}
@TestMetadata("ifBreakAssignInsideWhileTrue.kt")
public void testIfBreakAssignInsideWhileTrue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.kt");
doTest(fileName);
}
@TestMetadata("ifBreakExprInsideWhileTrue.kt")
public void testIfBreakExprInsideWhileTrue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.kt");
doTest(fileName);
}
@TestMetadata("ifElseBlockInsideDoWhile.kt")
public void testIfElseBlockInsideDoWhile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/ifElseBlockInsideDoWhile.kt");
@@ -11186,6 +11216,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("leftElvisBreakInsideWhileTrue.kt")
public void testLeftElvisBreakInsideWhileTrue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.kt");
doTest(fileName);
}
@TestMetadata("nestedDoWhile.kt")
public void testNestedDoWhile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/nestedDoWhile.kt");
@@ -11228,12 +11264,30 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("plusAssignWhenInsideDoWhile.kt")
public void testPlusAssignWhenInsideDoWhile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.kt");
doTest(fileName);
}
@TestMetadata("useInsideDoWhile.kt")
public void testUseInsideDoWhile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/useInsideDoWhile.kt");
doTest(fileName);
}
@TestMetadata("whenInsideWhileTrue.kt")
public void testWhenInsideWhileTrue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.kt");
doTest(fileName);
}
@TestMetadata("whenReturnInsideWhileTrue.kt")
public void testWhenReturnInsideWhileTrue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.kt");
doTest(fileName);
}
@TestMetadata("whileInCondition.kt")
public void testWhileInCondition() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/whileInCondition.kt");
@@ -298,7 +298,7 @@ public abstract class ExpectedResolveData {
PsiElement element = position.getElement();
JetExpression expression = getAncestorOfType(JetExpression.class, element);
JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
JetType expressionType = bindingContext.getType(expression);
TypeConstructor expectedTypeConstructor;
if (typeName.startsWith(STANDARD_PREFIX)) {
String name = typeName.substring(STANDARD_PREFIX.length());
@@ -61,6 +61,7 @@ import org.jetbrains.kotlin.idea.JetLanguage;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
@@ -69,6 +70,8 @@ import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil;
import org.jetbrains.kotlin.resolve.lazy.LazyResolveTestUtil;
import org.jetbrains.kotlin.test.util.UtilPackage;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
import org.jetbrains.kotlin.util.slicedMap.SlicedMap;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
@@ -141,6 +144,12 @@ public class JetTestUtils {
public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
return ImmutableMap.of();
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
return DUMMY_TRACE.getType(expression);
}
};
}
@@ -166,6 +175,17 @@ public class JetTestUtils {
return Collections.emptySet();
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression);
return typeInfo != null ? typeInfo.getType() : null;
}
@Override
public void recordType(@NotNull JetExpression expression, @Nullable JetType type) {
}
@Override
public void report(@NotNull Diagnostic diagnostic) {
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
@@ -202,6 +222,12 @@ public class JetTestUtils {
public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
return ImmutableMap.of();
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
return DUMMY_EXCEPTION_ON_ERROR_TRACE.getType(expression);
}
};
}
@@ -225,6 +251,16 @@ public class JetTestUtils {
return Collections.emptySet();
}
@Nullable
@Override
public JetType getType(@NotNull JetExpression expression) {
return null;
}
@Override
public void recordType(@NotNull JetExpression expression, @Nullable JetType type) {
}
@Override
public void report(@NotNull Diagnostic diagnostic) {
if (diagnostic.getSeverity() == Severity.ERROR) {
@@ -96,7 +96,7 @@ public class ReferenceVariantsHelper(
val expressionType = if (useRuntimeReceiverType)
getQualifierRuntimeType(receiverExpression)
else
context[BindingContext.EXPRESSION_TYPE, receiverExpression]
context.getType(receiverExpression)
if (expressionType != null && !expressionType.isError()) {
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
val dataFlowInfo = context.getDataFlowInfo(expression)
@@ -164,7 +164,7 @@ public class ReferenceVariantsHelper(
val receiverData = getExplicitReceiverData(expression)
if (receiverData != null) {
val receiverExpression = receiverData.first
val expressionType = context[BindingContext.EXPRESSION_TYPE, receiverExpression] ?: return ReceiversData.Empty
val expressionType = context.getType(receiverExpression) ?: return ReceiversData.Empty
return ReceiversData(listOf(ExpressionReceiver(receiverExpression, expressionType)), receiverData.second)
}
else {
@@ -174,7 +174,7 @@ public class ReferenceVariantsHelper(
}
private fun getQualifierRuntimeType(receiver: JetExpression): JetType? {
val type = context[BindingContext.EXPRESSION_TYPE, receiver]
val type = context.getType(receiver)
if (type != null && TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type)) {
val evaluator = receiver.getContainingFile().getCopyableUserData(JetCodeFragment.RUNTIME_TYPE_EVALUATOR)
return evaluator?.invoke(receiver)
@@ -127,7 +127,7 @@ public class OperatorToFunctionIntention : JetSelfTargetingIntention<JetExpressi
val context = element.analyze()
val functionCandidate = element.getResolvedCall(context)
val functionName = functionCandidate?.getCandidateDescriptor()?.getName().toString()
val elemType = context[BindingContext.EXPRESSION_TYPE, left]
val elemType = context.getType(left)
val transformation = when (op) {
JetTokens.PLUS -> "$leftText.plus($rightText)"
@@ -139,7 +139,7 @@ class ExpectedInfos(
val callOperationNode: ASTNode?
if (parent is JetQualifiedExpression && callElement == parent.getSelectorExpression()) {
val receiverExpression = parent.getReceiverExpression()
val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, receiverExpression]
val expressionType = bindingContext.getType(receiverExpression)
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression]
if (expressionType != null) {
receiver = ExpressionReceiver(receiverExpression, expressionType)
@@ -231,7 +231,7 @@ class ExpectedInfos(
|| operationToken == JetTokens.EQEQEQ || operationToken == JetTokens.EXCLEQEQEQ) {
val otherOperand = if (expressionWithType == binaryExpression.getRight()) binaryExpression.getLeft() else binaryExpression.getRight()
if (otherOperand != null) {
val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, otherOperand] ?: return null
val expressionType = bindingContext.getType(otherOperand) ?: return null
return listOf(ExpectedInfo(expressionType, expectedNameFromExpression(otherOperand), null))
}
}
@@ -248,7 +248,7 @@ class ExpectedInfos(
ifExpression.getElse() -> {
val ifExpectedInfo = calculate(ifExpression)
val thenType = bindingContext[BindingContext.EXPRESSION_TYPE, ifExpression.getThen()]
val thenType = bindingContext.getType(ifExpression.getThen())
if (thenType != null)
ifExpectedInfo?.filter { it.type.isSubtypeOf(thenType) }
else
@@ -265,7 +265,7 @@ class ExpectedInfos(
val operationToken = binaryExpression.getOperationToken()
if (operationToken == JetTokens.ELVIS && expressionWithType == binaryExpression.getRight()) {
val leftExpression = binaryExpression.getLeft() ?: return null
val leftType = bindingContext[BindingContext.EXPRESSION_TYPE, leftExpression]
val leftType = bindingContext.getType(leftExpression)
val leftTypeNotNullable = leftType?.makeNotNullable()
val expectedInfos = calculate(binaryExpression)
if (expectedInfos != null) {
@@ -294,7 +294,7 @@ class ExpectedInfos(
val whenExpression = entry.getParent() as JetWhenExpression
val subject = whenExpression.getSubjectExpression()
if (subject != null) {
val subjectType = bindingContext[BindingContext.EXPRESSION_TYPE, subject] ?: return null
val subjectType = bindingContext.getType(subject) ?: return null
return listOf(ExpectedInfo(subjectType, null, null))
}
else {
@@ -298,7 +298,7 @@ class SmartCompletion(
}
}
val subjectType = bindingContext[BindingContext.EXPRESSION_TYPE, subject] ?: return setOf()
val subjectType = bindingContext.getType(subject) ?: return setOf()
val classDescriptor = TypeUtils.getClassDescriptor(subjectType)
if (classDescriptor != null && DescriptorUtils.isEnumClass(classDescriptor)) {
val conditions = whenExpression.getEntries()
@@ -410,7 +410,7 @@ class SmartCompletion(
val operationToken = binaryExpression.getOperationToken()
if (operationToken != JetTokens.IN_KEYWORD && operationToken != JetTokens.NOT_IN || expressionWithType != binaryExpression.getRight()) return null
val leftOperandType = bindingContext.get(BindingContext.EXPRESSION_TYPE, binaryExpression.getLeft()) ?: return null
val leftOperandType = bindingContext.getType(binaryExpression.getLeft()) ?: return null
val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expressionWithType)
val detector = TypesWithContainsDetector(scope, leftOperandType, project, moduleDescriptor)
@@ -122,7 +122,7 @@ public class KotlinIndicesHelper(
if (receiverPair != null) {
val (receiverExpression, callType) = receiverPair
val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, receiverExpression]
val expressionType = bindingContext.getType(receiverExpression)
if (expressionType == null || expressionType.isError()) return emptyList()
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
@@ -65,7 +65,7 @@ class SmartCastCalculator(val bindingContext: BindingContext, val containingDecl
val dataFlowValueToVariable: (DataFlowValue) -> VariableDescriptor?
if (receiver != null) {
val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver] ?: return ProcessDataFlowInfoResult()
val receiverType = bindingContext.getType(receiver) ?: return ProcessDataFlowInfoResult()
val receiverId = DataFlowValueFactory.createDataFlowValue(receiver, receiverType, bindingContext, containingDeclarationOrModule).getId()
dataFlowValueToVariable = { value ->
val id = value.getId()
@@ -35,7 +35,7 @@ fun DeclarationDescriptorWithVisibility.isVisible(
if (bindingContext == null || element == null) return false
val receiver = element.getReceiverExpression()
val type = receiver?.let { bindingContext.get(BindingContext.EXPRESSION_TYPE, it) }
val type = receiver?.let { bindingContext.getType(it) }
val explicitReceiver = type?.let { ExpressionReceiver(receiver, it) }
if (explicitReceiver != null) {
@@ -69,7 +69,7 @@ public class JetNameSuggester {
ArrayList<String> result = new ArrayList<String>();
BindingContext bindingContext = ResolvePackage.analyze(expression, BodyResolveMode.FULL);
JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
JetType jetType = bindingContext.getType(expression);
if (jetType != null) {
addNamesForType(result, jetType, validator);
}
@@ -50,7 +50,7 @@ public class ShowExpressionTypeAction extends AnAction {
else {
int offset = editor.getCaretModel().getOffset();
expression = PsiTreeUtil.getParentOfType(psiFile.findElementAt(offset), JetExpression.class);
while (expression != null && bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) == null) {
while (expression != null && bindingContext.getType(expression) == null) {
expression = PsiTreeUtil.getParentOfType(expression, JetExpression.class);
}
if (expression != null) {
@@ -59,7 +59,7 @@ public class ShowExpressionTypeAction extends AnAction {
}
}
if (expression != null) {
JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
JetType type = bindingContext.getType(expression);
if (type != null) {
HintManager.getInstance().showInformationHint(editor, "<html>" + DescriptorRenderer.HTML.renderType(type) + "</html>");
}
@@ -135,7 +135,7 @@ public class CheckPartialBodyResolveAction : AnAction() {
builder.append(" resolves to ${target?.presentation()}")
}
val type = bindingContext[BindingContext.EXPRESSION_TYPE, expression]
val type = bindingContext.getType(expression)
if (type != null) {
builder.append(" has type ${type.presentation()}")
}
@@ -77,7 +77,7 @@ public class FindImplicitNothingAction : AnAction() {
try {
val bindingContext = resolutionFacade.analyze(expression)
val type = bindingContext[BindingContext.EXPRESSION_TYPE, expression] ?: return
val type = bindingContext.getType(expression) ?: return
if (KotlinBuiltIns.isNothing(type) && !expression.hasExplicitNothing(bindingContext)) { //TODO: what about nullable Nothing?
found.add(expression)
}
@@ -44,7 +44,7 @@ public abstract class KotlinExpressionSurrounder implements Surrounder {
if (expression instanceof JetCallExpression && expression.getParent() instanceof JetQualifiedExpression) {
return false;
}
JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).get(BindingContext.EXPRESSION_TYPE, expression);
JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).getType(expression);
if (type == null || type.equals(KotlinBuiltIns.getInstance().getUnitType())) {
return false;
}
@@ -42,7 +42,7 @@ public class KotlinNotSurrounder extends KotlinExpressionSurrounder {
@Override
public boolean isApplicable(@NotNull JetExpression expression) {
JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).get(BindingContext.EXPRESSION_TYPE, expression);
JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).getType(expression);
return KotlinBuiltIns.getInstance().getBooleanType().equals(type);
}
@@ -52,7 +52,7 @@ public class KotlinRuntimeTypeCastSurrounder: KotlinExpressionSurrounder() {
if (file !is JetCodeFragment) return false
val context = file.analyzeFully()
val type = context[BindingContext.EXPRESSION_TYPE, expression]
val type = context.getType(expression)
if (type == null) return false
return TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type)
@@ -70,7 +70,7 @@ public class KotlinWhenSurrounder extends KotlinExpressionSurrounder {
}
private String getCodeTemplate(JetExpression expression) {
JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).get(BindingContext.EXPRESSION_TYPE, expression);
JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).getType(expression);
if (type != null) {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.ENUM_CLASS) {
@@ -76,5 +76,5 @@ public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndepe
private fun String.quote(quote: String) = quote + this + quote
private fun JetExpression.isStringExpression() = KotlinBuiltIns.isString(BindingContextUtils.getRecordedTypeInfo(this, analyze())?.getType())
private fun JetExpression.isStringExpression() = KotlinBuiltIns.isString(BindingContextUtils.getRecordedTypeInfo(this, analyze())?.type)
}
@@ -94,7 +94,7 @@ public class ConvertToExpressionBodyIntention : JetSelfTargetingOffsetIndependen
val declaredType = (descriptor as? CallableDescriptor)?.getReturnType() ?: return false
val scope = scopeExpression.analyze()[BindingContext.RESOLUTION_SCOPE, scopeExpression] ?: return false
val expressionType = expression.analyzeInContext(scope)[BindingContext.EXPRESSION_TYPE, expression] ?: return false
val expressionType = expression.analyzeInContext(scope).getType(expression) ?: return false
return expressionType.isSubtypeOf(declaredType)
}
@@ -39,7 +39,7 @@ public class ConvertToStringTemplateIntention : JetSelfTargetingOffsetIndependen
override fun isApplicableTo(element: JetBinaryExpression): Boolean {
if (element.getOperationToken() != JetTokens.PLUS) return false
val elementType = BindingContextUtils.getRecordedTypeInfo(element, element.analyze())?.getType()
val elementType = BindingContextUtils.getRecordedTypeInfo(element, element.analyze())?.type
if (!KotlinBuiltIns.isString(elementType)) return false
val left = element.getLeft() ?: return false
@@ -80,7 +80,7 @@ public class ConvertToStringTemplateIntention : JetSelfTargetingOffsetIndependen
val context = expression.analyze()
val constant = ConstantExpressionEvaluator.evaluate(expression, DelegatingBindingTrace(context, "Trace for evaluating constant"), null)
if (constant is IntegerValueTypeConstant) {
val elementType = BindingContextUtils.getRecordedTypeInfo(expression, context)?.getType()!!
val elementType = BindingContextUtils.getRecordedTypeInfo(expression, context)?.type!!
constant.getValue(elementType).toString()
}
else {
@@ -83,7 +83,7 @@ public open class ReplaceWithInfixFunctionCallIntention : JetSelfTargetingIntent
val valueArguments = element.getValueArgumentList()?.getArguments() ?: listOf<JetValueArgument>()
val functionLiteralArguments = element.getFunctionLiteralArguments()
val bindingContext = parent.analyze()
val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver]
val receiverType = bindingContext.getType(receiver)
if (receiverType == null) {
if (bindingContext[BindingContext.QUALIFIER, receiver] != null) {
intentionFailed(editor, "package.call")
@@ -47,7 +47,7 @@ fun specifyTypeExplicitly(declaration: JetNamedFunction, typeReference: JetTypeR
fun expressionType(expression: JetExpression): JetType? {
val bindingContext = expression.analyze()
return bindingContext.get(BindingContext.EXPRESSION_TYPE, expression)
return bindingContext.getType(expression)
}
fun functionReturnType(function: JetNamedFunction): JetType? {
@@ -45,9 +45,7 @@ public class DeclarationUtils {
private static JetType getPropertyTypeIfNeeded(@NotNull JetProperty property) {
if (property.getTypeReference() != null) return null;
JetType type = ResolvePackage.analyze(property, BodyResolveMode.FULL).get(
BindingContext.EXPRESSION_TYPE, property.getInitializer()
);
JetType type = ResolvePackage.analyze(property, BodyResolveMode.FULL).getType(property.getInitializer());
return type == null || type.isError() ? null : type;
}
@@ -330,7 +330,7 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith
private static boolean isArgumentTypeValid(BindingContext bindingContext, JetValueArgument argument, ValueParameterDescriptor param) {
if (argument.getArgumentExpression() != null) {
JetType paramType = getActualParameterType(param);
JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
JetType exprType = bindingContext.getType(argument.getArgumentExpression());
return exprType == null || JetTypeChecker.DEFAULT.isSubtypeOf(exprType, paramType);
}
@@ -138,7 +138,7 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix {
if (i < parameters.size()) {
validator.validateName(parameters.get(i).getName().asString());
JetType argumentType = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null;
JetType argumentType = expression != null ? bindingContext.getType(expression) : null;
JetType parameterType = parameters.get(i).getType();
if (argumentType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) {
@@ -74,7 +74,7 @@ public class AddNameToArgumentFix extends JetIntentionAction<JetValueArgument> {
if (resolvedCall == null) return Collections.emptyList();
CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
JetType type = context.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
JetType type = context.getType(argument.getArgumentExpression());
Set<String> usedParameters = QuickFixUtil.getUsedParameters(callElement, null, callableDescriptor);
List<String> names = Lists.newArrayList();
for (ValueParameterDescriptor parameter: callableDescriptor.getValueParameters()) {
@@ -65,7 +65,7 @@ public class CastExpressionFix extends JetIntentionAction<JetExpression> {
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (!super.isAvailable(project, editor, file)) return false;
BindingContext context = ResolvePackage.analyzeFully((JetFile) file);
JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, element);
JetType expressionType = context.getType(element);
return expressionType != null && JetTypeChecker.DEFAULT.isSubtypeOf(type, expressionType);
}
@@ -58,7 +58,7 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFu
functionLiteralReturnTypeRef = functionLiteralExpression.getFunctionLiteral().getTypeReference();
BindingContext context = ResolvePackage.analyzeFully(functionLiteralExpression.getContainingJetFile());
JetType functionLiteralType = context.get(BindingContext.EXPRESSION_TYPE, functionLiteralExpression);
JetType functionLiteralType = context.getType(functionLiteralExpression);
assert functionLiteralType != null : "Type of function literal not available in binding context";
ClassDescriptor functionClass = KotlinBuiltIns.getInstance().getFunction(functionLiteralType.getArguments().size() - 1);
@@ -118,7 +118,7 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
) {
String name = getNewArgumentName(argument, validator);
JetExpression expression = argument.getArgumentExpression();
JetType type = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null;
JetType type = expression != null ? bindingContext.getType(expression) : null;
type = type != null ? type : KotlinBuiltIns.getInstance().getNullableAnyType();
JetParameterInfo parameterInfo = new JetParameterInfo(-1, name, type, null, "", JetValVar.None, null);
parameterInfo.setCurrentTypeText(IdeDescriptorRenderers.SOURCE_CODE.renderType(type));
@@ -135,7 +135,7 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
assert i < arguments .size(); // number of parameters must not be greater than the number of arguments (it's called only for TOO_MANY_ARGUMENTS error)
JetExpression argumentExpression = arguments.get(i).getArgumentExpression();
JetType argumentType =
argumentExpression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, argumentExpression) : null;
argumentExpression != null ? bindingContext.getType(argumentExpression) : null;
JetType parameterType = parameters.get(i).getType();
if (argumentType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) {
@@ -127,7 +127,7 @@ private class LambdaToFunctionExpression(
init {
val bindingContext = functionLiteralExpression.analyze()
val functionLiteralType = bindingContext.get(BindingContext.EXPRESSION_TYPE, functionLiteralExpression)
val functionLiteralType = bindingContext.getType(functionLiteralExpression)
assert(functionLiteralType != null && KotlinBuiltIns.isFunctionOrExtensionFunctionType(functionLiteralType)) {
"Broken function type for expression: ${functionLiteralExpression.getText()}, at: ${DiagnosticUtils.atLocation(functionLiteralExpression)}"
}
@@ -80,7 +80,7 @@ public class QuickFixFactoryForTypeMismatchError extends JetIntentionActionsFact
DiagnosticWithParameters2<JetConstantExpression, String, JetType> diagnosticWithParameters =
Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic);
expectedType = diagnosticWithParameters.getB();
expressionType = context.get(BindingContext.EXPRESSION_TYPE, expression);
expressionType = context.getType(expression);
if (expressionType == null) {
LOG.error("No type inferred: " + expression.getText());
return Collections.emptyList();
@@ -155,7 +155,7 @@ public class QuickFixFactoryForTypeMismatchError extends JetIntentionActionsFact
JetParameter correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument);
JetType valueArgumentType = diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE
? expressionType
: context.get(BindingContext.EXPRESSION_TYPE, valueArgument.getArgumentExpression());
: context.getType(valueArgument.getArgumentExpression());
if (correspondingParameter != null && valueArgumentType != null) {
JetCallableDeclaration callable = PsiTreeUtil.getParentOfType(correspondingParameter, JetCallableDeclaration.class, true);
JetScope scope = callable != null ? JetScopeUtils.getResolutionScope(callable, context) : null;
@@ -55,7 +55,7 @@ private fun DeclarationDescriptor.render(
private fun JetType.render(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fq: Boolean): String {
val arguments = getArguments().map { it.getType().render(typeParameterNameMap, fq) }
val typeString = getConstructor().getDeclarationDescriptor()!!.render(typeParameterNameMap, fq)
val typeArgumentString = if (arguments.notEmpty) arguments.joinToString(", ", "<", ">") else ""
val typeArgumentString = if (arguments.isNotEmpty()) arguments.joinToString(", ", "<", ">") else ""
val nullifier = if (isMarkedNullable()) "?" else ""
return "$typeString$typeArgumentString$nullifier"
}
@@ -73,10 +73,10 @@ private fun getTypeParameterNamesNotInScope(typeParameters: Collection<TypeParam
fun JetType.getTypeParameters(): Set<TypeParameterDescriptor> {
val typeParameters = LinkedHashSet<TypeParameterDescriptor>()
val arguments = getArguments()
if (arguments.empty) {
if (arguments.isEmpty()) {
val descriptor = getConstructor().getDeclarationDescriptor()
if (descriptor is TypeParameterDescriptor) {
typeParameters.add(descriptor as TypeParameterDescriptor)
typeParameters.add(descriptor)
}
}
else {
@@ -100,9 +100,9 @@ fun JetExpression.guessTypes(
&& getNonStrictParentOfType<JetAnnotationEntry>() == null) return array(builtIns.getUnitType())
// if we know the actual type of the expression
val theType1 = context[BindingContext.EXPRESSION_TYPE, this]
val theType1 = context.getType(this)
if (theType1 != null) {
val dataFlowInfo = context[BindingContext.EXPRESSION_DATA_FLOW_INFO, this]
val dataFlowInfo = context[BindingContext.EXPRESSION_TYPE_INFO, this]?.dataFlowInfo
val possibleTypes = dataFlowInfo?.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(this, theType1, context, module))
return if (possibleTypes != null && possibleTypes.isNotEmpty()) possibleTypes.copyToArray() else array(theType1)
}
@@ -117,12 +117,12 @@ fun JetExpression.guessTypes(
return when {
this is JetTypeConstraint -> {
// expression itself is a type assertion
val constraint = (this as JetTypeConstraint)
val constraint = this
array(context[BindingContext.TYPE, constraint.getBoundTypeReference()]!!)
}
parent is JetTypeConstraint -> {
// expression is on the left side of a type assertion
val constraint = (parent as JetTypeConstraint)
val constraint = parent
array(context[BindingContext.TYPE, constraint.getBoundTypeReference()]!!)
}
this is JetMultiDeclarationEntry -> {
@@ -162,7 +162,7 @@ fun JetExpression.guessTypes(
variable.guessType(context)
}
}
parent is JetPropertyDelegate && module != null -> {
parent is JetPropertyDelegate -> {
val property = context[BindingContext.DECLARATION_TO_DESCRIPTOR, parent.getParent() as JetProperty] as PropertyDescriptor
val delegateClassName = if (property.isVar()) "ReadWriteProperty" else "ReadOnlyProperty"
val delegateClass = module.resolveTopLevelClass(FqName("kotlin.properties.$delegateClassName"))
@@ -180,7 +180,7 @@ fun JetExpression.guessTypes(
}
private fun JetNamedDeclaration.guessType(context: BindingContext): Array<JetType> {
val expectedTypes = SearchUtils.findAllReferences(this, getUseScope())!!.stream().map { ref ->
val expectedTypes = SearchUtils.findAllReferences(this, getUseScope())!!.sequence().map { ref ->
if (ref is JetSimpleNameReference) {
context[BindingContext.EXPECTED_EXPRESSION_TYPE, ref.expression]
}

Some files were not shown because too many files have changed in this diff Show More