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:
@@ -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");
|
||||
|
||||
+1
-1
@@ -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)";
|
||||
|
||||
|
||||
+3
-3
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+21
-25
@@ -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.*;
|
||||
|
||||
+1
-2
@@ -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())
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -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;
|
||||
}
|
||||
}
|
||||
+131
-119
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+58
-40
@@ -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
|
||||
|
||||
-2
@@ -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
|
||||
|
||||
-1
@@ -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
|
||||
|
||||
+9
-15
@@ -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;
|
||||
|
||||
+3
-3
@@ -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")
|
||||
|
||||
-1
@@ -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> {
|
||||
|
||||
|
||||
+14
-28
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+35
-29
@@ -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
|
||||
|
||||
+9
-8
@@ -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)
|
||||
}
|
||||
+14
-8
@@ -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)
|
||||
}
|
||||
+11
@@ -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()
|
||||
}
|
||||
+3
@@ -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) {
|
||||
|
||||
+3
-3
@@ -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)
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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>");
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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)}"
|
||||
}
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+9
-9
@@ -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
Reference in New Issue
Block a user