@@ -68,6 +68,7 @@ public interface BindingContext {
|
|||||||
WritableSlice<JetExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = Slices.createSimpleSlice();
|
WritableSlice<JetExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = Slices.createSimpleSlice();
|
||||||
WritableSlice<JetTypeReference, JetType> TYPE = Slices.createSimpleSlice();
|
WritableSlice<JetTypeReference, JetType> TYPE = Slices.createSimpleSlice();
|
||||||
WritableSlice<JetExpression, JetType> EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
|
WritableSlice<JetExpression, JetType> EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
|
||||||
|
WritableSlice<JetExpression, DataFlowInfo> EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice<JetExpression, DataFlowInfo>(DO_NOTHING);
|
||||||
|
|
||||||
WritableSlice<JetReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET = new BasicWritableSlice<JetReferenceExpression, DeclarationDescriptor>(DO_NOTHING);
|
WritableSlice<JetReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET = new BasicWritableSlice<JetReferenceExpression, DeclarationDescriptor>(DO_NOTHING);
|
||||||
WritableSlice<JetElement, ResolvedCall<? extends CallableDescriptor>> RESOLVED_CALL = new BasicWritableSlice<JetElement, ResolvedCall<? extends CallableDescriptor>>(DO_NOTHING);
|
WritableSlice<JetElement, ResolvedCall<? extends CallableDescriptor>> RESOLVED_CALL = new BasicWritableSlice<JetElement, ResolvedCall<? extends CallableDescriptor>>(DO_NOTHING);
|
||||||
|
|||||||
@@ -767,6 +767,7 @@ public class CallResolver {
|
|||||||
|
|
||||||
private <D extends CallableDescriptor, F extends D> ResolutionStatus checkValueArgumentTypes(CallResolutionContext<D, F> context) {
|
private <D extends CallableDescriptor, F extends D> ResolutionStatus checkValueArgumentTypes(CallResolutionContext<D, F> context) {
|
||||||
ResolutionStatus result = SUCCESS;
|
ResolutionStatus result = SUCCESS;
|
||||||
|
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : context.candidateCall.getValueArguments().entrySet()) {
|
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : context.candidateCall.getValueArguments().entrySet()) {
|
||||||
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
||||||
ResolvedValueArgument resolvedArgument = entry.getValue();
|
ResolvedValueArgument resolvedArgument = entry.getValue();
|
||||||
@@ -777,7 +778,9 @@ public class CallResolver {
|
|||||||
if (expression == null) continue;
|
if (expression == null) continue;
|
||||||
|
|
||||||
JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
|
JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
|
||||||
JetType type = expressionTypingServices.getType(context.scope, expression, expectedType, context.dataFlowInfo, context.candidateCall.getTrace());
|
JetTypeInfo typeInfo = expressionTypingServices.getTypeInfo(context.scope, expression, expectedType, dataFlowInfo, context.candidateCall.getTrace());
|
||||||
|
JetType type = typeInfo.getType();
|
||||||
|
dataFlowInfo = dataFlowInfo.and(typeInfo.getDataFlowInfo());
|
||||||
if (type == null || ErrorUtils.isErrorType(type)) {
|
if (type == null || ErrorUtils.isErrorType(type)) {
|
||||||
context.candidateCall.argumentHasNoType();
|
context.candidateCall.argumentHasNoType();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
|
|||||||
|
|
||||||
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
|
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
|
||||||
private final Map<ValueParameterDescriptor, JetType> autoCasts = Maps.newHashMap();
|
private final Map<ValueParameterDescriptor, JetType> autoCasts = Maps.newHashMap();
|
||||||
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newHashMap();
|
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newLinkedHashMap();
|
||||||
private boolean someArgumentHasNoType = false;
|
private boolean someArgumentHasNoType = false;
|
||||||
private TemporaryBindingTrace trace;
|
private TemporaryBindingTrace trace;
|
||||||
private ResolutionStatus status = UNKNOWN_STATUS;
|
private ResolutionStatus status = UNKNOWN_STATUS;
|
||||||
|
|||||||
+70
-43
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.calls.CallMaker;
|
|||||||
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
|
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResultsUtil;
|
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResultsUtil;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.*;
|
import org.jetbrains.jet.lang.resolve.constants.*;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
||||||
@@ -72,9 +73,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
public JetTypeInfo visitSimpleNameExpression(JetSimpleNameExpression expression, ExpressionTypingContext context) {
|
public JetTypeInfo visitSimpleNameExpression(JetSimpleNameExpression expression, ExpressionTypingContext context) {
|
||||||
// TODO : other members
|
// TODO : other members
|
||||||
// TODO : type substitutions???
|
// TODO : type substitutions???
|
||||||
JetType type = DataFlowUtils.checkType(getSelectorReturnType(NO_RECEIVER, null, expression, context), expression, context);
|
JetTypeInfo typeInfo = getSelectorReturnTypeInfo(NO_RECEIVER, null, expression, context);
|
||||||
|
JetType type = DataFlowUtils.checkType(typeInfo.getType(), expression, context);
|
||||||
ExpressionTypingUtils.checkWrappingInRef(expression, context);
|
ExpressionTypingUtils.checkWrappingInRef(expression, context);
|
||||||
return JetTypeInfo.create(type, context.dataFlowInfo); // TODO : Extensions to this
|
return JetTypeInfo.create(type, typeInfo.getDataFlowInfo()); // TODO : Extensions to this
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -192,37 +194,41 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
public JetTypeInfo visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext context) {
|
public JetTypeInfo visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext context) {
|
||||||
JetTypeReference right = expression.getRight();
|
JetTypeReference right = expression.getRight();
|
||||||
JetType result = null;
|
JetType result = null;
|
||||||
|
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||||
if (right != null) {
|
if (right != null) {
|
||||||
JetType targetType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, right, context.trace, true);
|
JetType targetType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, right, context.trace, true);
|
||||||
|
|
||||||
|
boolean tryWithNoExpectedType = true;
|
||||||
if (isTypeFlexible(expression.getLeft()) || expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) {
|
if (isTypeFlexible(expression.getLeft()) || expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) {
|
||||||
TemporaryBindingTrace temporaryTraceWithExpectedType = TemporaryBindingTrace.create(context.trace);
|
TemporaryBindingTrace temporaryTraceWithExpectedType = TemporaryBindingTrace.create(context.trace);
|
||||||
boolean success = checkBinaryWithTypeRHS(expression, context.replaceBindingTrace(temporaryTraceWithExpectedType).replaceExpectedType(targetType), targetType);
|
ExpressionTypingContext contextWithTemporaryTrace = context.replaceBindingTrace(temporaryTraceWithExpectedType).replaceExpectedType(targetType);
|
||||||
if (success) {
|
JetTypeInfo typeInfo = facade.getTypeInfo(expression.getLeft(), contextWithTemporaryTrace);
|
||||||
|
if (typeInfo.getType() != null && checkBinaryWithTypeRHS(expression, contextWithTemporaryTrace, targetType, typeInfo.getType())) {
|
||||||
temporaryTraceWithExpectedType.commit();
|
temporaryTraceWithExpectedType.commit();
|
||||||
}
|
dataFlowInfo = typeInfo.getDataFlowInfo();
|
||||||
else {
|
tryWithNoExpectedType = false;
|
||||||
checkBinaryWithTypeRHS(expression, context.replaceExpectedType(NO_EXPECTED_TYPE), targetType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
checkBinaryWithTypeRHS(expression, context.replaceExpectedType(NO_EXPECTED_TYPE), targetType);
|
if (tryWithNoExpectedType) {
|
||||||
|
ExpressionTypingContext contextWithNoExpectedType = context.replaceExpectedType(NO_EXPECTED_TYPE);
|
||||||
|
JetTypeInfo typeInfo = facade.getTypeInfo(expression.getLeft(), contextWithNoExpectedType);
|
||||||
|
if (typeInfo.getType() != null) {
|
||||||
|
checkBinaryWithTypeRHS(expression, contextWithNoExpectedType, targetType, typeInfo.getType());
|
||||||
|
dataFlowInfo = typeInfo.getDataFlowInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IElementType operationType = expression.getOperationSign().getReferencedNameElementType();
|
IElementType operationType = expression.getOperationSign().getReferencedNameElementType();
|
||||||
result = operationType == JetTokens.AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType;
|
result = operationType == JetTokens.AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
facade.getTypeInfo(expression.getLeft(), context.replaceExpectedType(NO_EXPECTED_TYPE));
|
dataFlowInfo = facade.getTypeInfo(expression.getLeft(), context.replaceExpectedType(NO_EXPECTED_TYPE)).getDataFlowInfo();
|
||||||
}
|
}
|
||||||
return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo);
|
return DataFlowUtils.checkType(result, expression, context, dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkBinaryWithTypeRHS(JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext context, @NotNull JetType targetType) {
|
private boolean checkBinaryWithTypeRHS(JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext context, @NotNull JetType targetType, JetType actualType) {
|
||||||
|
|
||||||
JetType actualType = facade.getTypeInfo(expression.getLeft(), context).getType();
|
|
||||||
if (actualType == null) return false;
|
|
||||||
|
|
||||||
JetSimpleNameExpression operationSign = expression.getOperationSign();
|
JetSimpleNameExpression operationSign = expression.getOperationSign();
|
||||||
IElementType operationType = operationSign.getReferencedNameElementType();
|
IElementType operationType = operationSign.getReferencedNameElementType();
|
||||||
if (operationType == JetTokens.COLON) {
|
if (operationType == JetTokens.COLON) {
|
||||||
@@ -537,11 +543,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
if (selectorExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo);
|
if (selectorExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||||
if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
|
if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
|
||||||
|
|
||||||
|
context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());
|
||||||
|
|
||||||
if (selectorExpression instanceof JetSimpleNameExpression) {
|
if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||||
propagateConstantValues(expression, context, (JetSimpleNameExpression) selectorExpression);
|
propagateConstantValues(expression, context, (JetSimpleNameExpression) selectorExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, receiverType), expression.getOperationTokenNode(), selectorExpression, context);
|
JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(new ExpressionReceiver(receiverExpression, receiverType), expression.getOperationTokenNode(), selectorExpression, context);
|
||||||
|
JetType selectorReturnType = selectorReturnTypeInfo.getType();
|
||||||
|
|
||||||
//TODO move further
|
//TODO move further
|
||||||
if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
|
if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
|
||||||
@@ -552,12 +561,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JetType result = selectorReturnType;
|
|
||||||
// TODO : this is suspicious: remove this code?
|
// TODO : this is suspicious: remove this code?
|
||||||
if (result != null) {
|
if (selectorReturnType != null) {
|
||||||
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, result);
|
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
|
||||||
}
|
}
|
||||||
return DataFlowUtils.checkType(result, expression, context, receiverTypeInfo.getDataFlowInfo());
|
return DataFlowUtils.checkType(selectorReturnType, expression, context, selectorReturnTypeInfo.getDataFlowInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void propagateConstantValues(JetQualifiedExpression expression, ExpressionTypingContext context, JetSimpleNameExpression selectorExpression) {
|
private void propagateConstantValues(JetQualifiedExpression expression, ExpressionTypingContext context, JetSimpleNameExpression selectorExpression) {
|
||||||
@@ -639,34 +647,33 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@NotNull
|
||||||
public JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
|
public JetTypeInfo getSelectorReturnTypeInfo(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
|
||||||
if (selectorExpression instanceof JetCallExpression) {
|
if (selectorExpression instanceof JetCallExpression) {
|
||||||
|
return getCallExpressionTypeInfo((JetCallExpression) selectorExpression, receiver, callOperationNode, context);
|
||||||
return getCallExpressionType((JetCallExpression) selectorExpression, receiver, callOperationNode, context);
|
|
||||||
}
|
}
|
||||||
else if (selectorExpression instanceof JetSimpleNameExpression) {
|
else if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||||
|
return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
|
||||||
return getSimpleNameExpressionType((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
|
|
||||||
}
|
}
|
||||||
else if (selectorExpression instanceof JetQualifiedExpression) {
|
else if (selectorExpression instanceof JetQualifiedExpression) {
|
||||||
|
|
||||||
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
|
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
|
||||||
JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression();
|
JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression();
|
||||||
JetType newReceiverType = getSelectorReturnType(receiver, callOperationNode, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
JetTypeInfo newReceiverTypeInfo = getSelectorReturnTypeInfo(receiver, callOperationNode, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
||||||
|
JetType newReceiverType = newReceiverTypeInfo.getType();
|
||||||
|
DataFlowInfo newReceiverDataFlowInfo = newReceiverTypeInfo.getDataFlowInfo();
|
||||||
JetExpression newSelectorExpression = qualifiedExpression.getSelectorExpression();
|
JetExpression newSelectorExpression = qualifiedExpression.getSelectorExpression();
|
||||||
if (newReceiverType != null && newSelectorExpression != null) {
|
if (newReceiverType != null && newSelectorExpression != null) {
|
||||||
return getSelectorReturnType(new ExpressionReceiver(newReceiverExpression, newReceiverType), qualifiedExpression.getOperationTokenNode(), newSelectorExpression, context);
|
return getSelectorReturnTypeInfo(new ExpressionReceiver(newReceiverExpression, newReceiverType), qualifiedExpression.getOperationTokenNode(), newSelectorExpression, context.replaceDataFlowInfo(newReceiverDataFlowInfo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
|
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
|
||||||
}
|
}
|
||||||
return null;
|
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@NotNull
|
||||||
private JetType getSimpleNameExpressionType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverDescriptor receiver,
|
private JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverDescriptor receiver,
|
||||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
|
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
|
||||||
|
|
||||||
boolean[] result = new boolean[1];
|
boolean[] result = new boolean[1];
|
||||||
@@ -675,7 +682,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceBindingTrace(traceForVariable), result);
|
JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceBindingTrace(traceForVariable), result);
|
||||||
if (result[0]) {
|
if (result[0]) {
|
||||||
traceForVariable.commit();
|
traceForVariable.commit();
|
||||||
return type;
|
return JetTypeInfo.create(type, context.dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
|
Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
|
||||||
@@ -685,15 +692,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
traceForFunction.commit();
|
traceForFunction.commit();
|
||||||
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
|
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
|
||||||
context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
|
context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
|
||||||
return functionDescriptor != null ? functionDescriptor.getReturnType() : null;
|
type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
|
||||||
|
return JetTypeInfo.create(type, context.dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
traceForVariable.commit();
|
traceForVariable.commit();
|
||||||
return null;
|
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@NotNull
|
||||||
private JetType getCallExpressionType(@NotNull JetCallExpression callExpression, @NotNull ReceiverDescriptor receiver,
|
private JetTypeInfo getCallExpressionTypeInfo(@NotNull JetCallExpression callExpression, @NotNull ReceiverDescriptor receiver,
|
||||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
|
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
|
||||||
|
|
||||||
boolean[] result = new boolean[1];
|
boolean[] result = new boolean[1];
|
||||||
@@ -709,7 +717,22 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
|
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
|
||||||
context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
|
context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
|
||||||
}
|
}
|
||||||
return functionDescriptor != null ? functionDescriptor.getReturnType() : null;
|
if (functionDescriptor == null) {
|
||||||
|
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||||
|
}
|
||||||
|
JetType type = functionDescriptor.getReturnType();
|
||||||
|
|
||||||
|
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||||
|
JetValueArgumentList argumentList = callExpression.getValueArgumentList();
|
||||||
|
if (argumentList != null) {
|
||||||
|
for (JetValueArgument argument : argumentList.getArguments()) {
|
||||||
|
JetExpression expression = argument.getArgumentExpression();
|
||||||
|
if (expression != null) {
|
||||||
|
dataFlowInfo = dataFlowInfo.and(facade.getTypeInfo(expression, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JetTypeInfo.create(type, dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
JetExpression calleeExpression = callExpression.getCalleeExpression();
|
JetExpression calleeExpression = callExpression.getCalleeExpression();
|
||||||
@@ -721,11 +744,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
traceForVariable.commit();
|
traceForVariable.commit();
|
||||||
context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression,
|
context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression,
|
||||||
type != null ? type : ErrorUtils.createErrorType("")));
|
type != null ? type : ErrorUtils.createErrorType("")));
|
||||||
return null;
|
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
traceForFunction.commit();
|
traceForFunction.commit();
|
||||||
return null;
|
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkSuper(@NotNull ReceiverDescriptor receiverDescriptor, @NotNull OverloadResolutionResults<? extends CallableDescriptor> results,
|
private static void checkSuper(@NotNull ReceiverDescriptor receiverDescriptor, @NotNull OverloadResolutionResults<? extends CallableDescriptor> results,
|
||||||
@@ -743,8 +766,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetTypeInfo visitCallExpression(JetCallExpression expression, ExpressionTypingContext context) {
|
public JetTypeInfo visitCallExpression(JetCallExpression expression, ExpressionTypingContext context) {
|
||||||
JetType expressionType = getCallExpressionType(expression, NO_RECEIVER, null, context);
|
JetTypeInfo expressionTypeInfo = getCallExpressionTypeInfo(expression, NO_RECEIVER, null, context);
|
||||||
return DataFlowUtils.checkType(expressionType, expression, context, context.dataFlowInfo);
|
return DataFlowUtils.checkType(expressionTypeInfo.getType(), expression, context, expressionTypeInfo.getDataFlowInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -784,6 +807,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
if (isKnownToBeNotNull(baseExpression, context)) {
|
if (isKnownToBeNotNull(baseExpression, context)) {
|
||||||
context.trace.report(UNNECESSARY_NOT_NULL_ASSERTION.on(operationSign, type));
|
context.trace.report(UNNECESSARY_NOT_NULL_ASSERTION.on(operationSign, type));
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
DataFlowValue value = DataFlowValueFactory.INSTANCE.createDataFlowValue(baseExpression, type, context.trace.getBindingContext());
|
||||||
|
dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL);
|
||||||
|
}
|
||||||
return DataFlowUtils.checkType(TypeUtils.makeNotNullable(type), expression, context, dataFlowInfo);
|
return DataFlowUtils.checkType(TypeUtils.makeNotNullable(type), expression, context, dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-4
@@ -22,17 +22,16 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetTypeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
/*package*/ interface ExpressionTypingInternals extends ExpressionTypingFacade {
|
/*package*/ interface ExpressionTypingInternals extends ExpressionTypingFacade {
|
||||||
|
|
||||||
@Nullable
|
@NotNull
|
||||||
JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context);
|
JetTypeInfo getSelectorReturnTypeInfo(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context);
|
||||||
|
|
||||||
boolean checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @Nullable JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context);
|
boolean checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @Nullable JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context);
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -115,12 +115,17 @@ public class ExpressionTypingServices {
|
|||||||
return ErrorUtils.createErrorType("Type for " + expression.getText());
|
return ErrorUtils.createErrorType("Type for " + expression.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@NotNull
|
||||||
public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
|
public JetTypeInfo getTypeInfo(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
|
||||||
ExpressionTypingContext context = ExpressionTypingContext.newContext(
|
ExpressionTypingContext context = ExpressionTypingContext.newContext(
|
||||||
this, trace, scope, dataFlowInfo, expectedType, false
|
this, trace, scope, dataFlowInfo, expectedType, false
|
||||||
);
|
);
|
||||||
return expressionTypingFacade.getTypeInfo(expression, context).getType();
|
return expressionTypingFacade.getTypeInfo(expression, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
|
||||||
|
return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace).getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public JetType getTypeWithNamespaces(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull BindingTrace trace) {
|
public JetType getTypeWithNamespaces(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull BindingTrace trace) {
|
||||||
|
|||||||
+12
-6
@@ -69,8 +69,8 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
|
public JetTypeInfo getSelectorReturnTypeInfo(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
|
||||||
return basic.getSelectorReturnType(receiver, callOperationNode, selectorExpression, context);
|
return basic.getSelectorReturnTypeInfo(receiver, callOperationNode, selectorExpression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -115,8 +115,11 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
|
|||||||
@NotNull
|
@NotNull
|
||||||
private JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
|
private JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
|
||||||
if (context.trace.get(BindingContext.PROCESSED, expression)) {
|
if (context.trace.get(BindingContext.PROCESSED, expression)) {
|
||||||
return JetTypeInfo.create(context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression),
|
DataFlowInfo dataFlowInfo = context.trace.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression);
|
||||||
context.dataFlowInfo);
|
if (dataFlowInfo == null) {
|
||||||
|
dataFlowInfo = context.dataFlowInfo;
|
||||||
|
}
|
||||||
|
return JetTypeInfo.create(context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression), dataFlowInfo);
|
||||||
}
|
}
|
||||||
JetTypeInfo result;
|
JetTypeInfo result;
|
||||||
try {
|
try {
|
||||||
@@ -128,7 +131,7 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.getType() instanceof DeferredType) {
|
if (result.getType() instanceof DeferredType) {
|
||||||
result = JetTypeInfo.create(((DeferredType) result.getType()).getActualType(), context.dataFlowInfo);
|
result = JetTypeInfo.create(((DeferredType) result.getType()).getActualType(), result.getDataFlowInfo());
|
||||||
}
|
}
|
||||||
if (result.getType() != null) {
|
if (result.getType() != null) {
|
||||||
context.trace.record(BindingContext.EXPRESSION_TYPE, expression, result.getType());
|
context.trace.record(BindingContext.EXPRESSION_TYPE, expression, result.getType());
|
||||||
@@ -144,7 +147,10 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
|
|||||||
context.trace.record(BindingContext.RESOLUTION_SCOPE, expression, context.scope);
|
context.trace.record(BindingContext.RESOLUTION_SCOPE, expression, context.scope);
|
||||||
}
|
}
|
||||||
context.trace.record(BindingContext.PROCESSED, expression);
|
context.trace.record(BindingContext.PROCESSED, expression);
|
||||||
return result;
|
if (result.getDataFlowInfo() != context.dataFlowInfo) {
|
||||||
|
context.trace.record(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression, result.getDataFlowInfo());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
+1
-1
@@ -239,7 +239,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
JetExpression decomposerExpression = pattern.getDecomposerExpression();
|
JetExpression decomposerExpression = pattern.getDecomposerExpression();
|
||||||
if (decomposerExpression != null) {
|
if (decomposerExpression != null) {
|
||||||
ReceiverDescriptor receiver = new TransientReceiver(subjectType);
|
ReceiverDescriptor receiver = new TransientReceiver(subjectType);
|
||||||
JetType selectorReturnType = facade.getSelectorReturnType(receiver, null, decomposerExpression, context);
|
JetType selectorReturnType = facade.getSelectorReturnTypeInfo(receiver, null, decomposerExpression, context).getType();
|
||||||
|
|
||||||
if (pattern.getArgumentList() != null) {
|
if (pattern.getArgumentList() != null) {
|
||||||
result.set(checkPatternType(pattern.getArgumentList(), selectorReturnType == null
|
result.set(checkPatternType(pattern.getArgumentList(), selectorReturnType == null
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ fun foo() {
|
|||||||
bar(<!TYPE_MISMATCH!>x<!>)
|
bar(<!TYPE_MISMATCH!>x<!>)
|
||||||
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
if (x == null) bar(x!!)
|
if (x == null) bar(x!!)
|
||||||
if (x != null) else bar(x!!)
|
if (x != null) else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
if (x == null) else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
if (x == null) else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) else bar(x!!)
|
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
if (x == null) bar(x!!) else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
if (x == null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ fun main(args : Array<String>) {
|
|||||||
val a : Int? = null
|
val a : Int? = null
|
||||||
val b : Int? = null
|
val b : Int? = null
|
||||||
a!! : Int
|
a!! : Int
|
||||||
a!! + 2
|
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!> + 2
|
||||||
a!!.plus(2)
|
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.plus(2)
|
||||||
a!!.plus(b!!)
|
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.plus(b!!)
|
||||||
2.plus(b!!)
|
2.plus(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
2 + b!!
|
2 + b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
||||||
|
|
||||||
val c = 1
|
val c = 1
|
||||||
c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
||||||
@@ -30,6 +30,6 @@ fun main(args : Array<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val <!UNUSED_VARIABLE!>f<!> : String = <!TYPE_MISMATCH!>a!!<!>
|
val <!UNUSED_VARIABLE!>f<!> : String = <!TYPE_MISMATCH!>a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!><!>
|
||||||
<!TYPE_MISMATCH!>a!!<!> : String
|
<!TYPE_MISMATCH!>a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!><!> : String
|
||||||
}
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
class Foo {
|
||||||
|
fun foo(a: Foo): Foo = a
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
val x: Foo? = null
|
||||||
|
val y: Foo? = null
|
||||||
|
|
||||||
|
x<!UNSAFE_CALL!>.<!>foo(<!TYPE_MISMATCH!>y<!>)
|
||||||
|
x!!.foo(<!TYPE_MISMATCH!>y<!>)
|
||||||
|
x.foo(y!!)
|
||||||
|
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(y<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
|
|
||||||
|
val a: Foo? = null
|
||||||
|
val b: Foo? = null
|
||||||
|
val c: Foo? = null
|
||||||
|
|
||||||
|
a<!UNSAFE_CALL!>.<!>foo(b<!UNSAFE_CALL!>.<!>foo(<!TYPE_MISMATCH!>c<!>))
|
||||||
|
a!!.foo(b<!UNSAFE_CALL!>.<!>foo(<!TYPE_MISMATCH!>c<!>))
|
||||||
|
a.foo(b!!.foo(<!TYPE_MISMATCH!>c<!>))
|
||||||
|
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(<!TYPE_MISMATCH!>c<!>))
|
||||||
|
a.foo(b.foo(c!!))
|
||||||
|
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(b.foo(c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
|
||||||
|
a.foo(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
|
||||||
|
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
|
||||||
|
|
||||||
|
val z: Foo? = null
|
||||||
|
z!!.foo(z<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//KT-2164 !! does not propagate nullability information
|
||||||
|
package kt2164
|
||||||
|
|
||||||
|
fun foo(x: Int): Int = x + 1
|
||||||
|
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
val x: Int? = null
|
||||||
|
|
||||||
|
foo(<!TYPE_MISMATCH!>x<!>)
|
||||||
|
|
||||||
|
if (x != null) {
|
||||||
|
foo(x)
|
||||||
|
foo(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
|
foo(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
foo(<!TYPE_MISMATCH!>x<!>)
|
||||||
|
|
||||||
|
if (x != null) {
|
||||||
|
foo(x)
|
||||||
|
foo(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
|
foo(x)
|
||||||
|
} else {
|
||||||
|
foo(<!TYPE_MISMATCH!>x<!>)
|
||||||
|
foo(x!!)
|
||||||
|
foo(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
foo(x)
|
||||||
|
foo(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
|
foo(x)
|
||||||
|
|
||||||
|
val y: Int? = null
|
||||||
|
y!!
|
||||||
|
y<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
||||||
|
foo(y)
|
||||||
|
foo(y<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//KT-2216 Nullability of a value determined in function parameter computation doesn't pass to code following
|
||||||
|
package kt2216
|
||||||
|
|
||||||
|
fun bar(y: Int, z: Int) = y + z
|
||||||
|
fun baz(a: Int, b: Int, c: Int, d: Int) = a + b + c + d
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val x: Int? = 0
|
||||||
|
|
||||||
|
bar(if (x != null) x else return, x)
|
||||||
|
x + 2
|
||||||
|
bar(x, x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
|
|
||||||
|
val y: Int? = 0
|
||||||
|
val z: Int? = 0
|
||||||
|
bar(if (y != null) y else <!TYPE_MISMATCH!>z<!>, <!TYPE_MISMATCH!>y<!>)
|
||||||
|
y <!UNSAFE_INFIX_CALL!>+<!> 2
|
||||||
|
baz(<!TYPE_MISMATCH!>y<!>, <!TYPE_MISMATCH!>y<!>, if (y == null) return else y, y)
|
||||||
|
baz(y, z!!, z, y)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user