@@ -68,6 +68,7 @@ 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, DataFlowInfo> EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice<JetExpression, DataFlowInfo>(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);
|
||||
|
||||
@@ -767,6 +767,7 @@ public class CallResolver {
|
||||
|
||||
private <D extends CallableDescriptor, F extends D> ResolutionStatus checkValueArgumentTypes(CallResolutionContext<D, F> context) {
|
||||
ResolutionStatus result = SUCCESS;
|
||||
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : context.candidateCall.getValueArguments().entrySet()) {
|
||||
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
||||
ResolvedValueArgument resolvedArgument = entry.getValue();
|
||||
@@ -777,7 +778,9 @@ public class CallResolver {
|
||||
if (expression == null) continue;
|
||||
|
||||
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)) {
|
||||
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<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 TemporaryBindingTrace trace;
|
||||
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.OverloadResolutionResultsUtil;
|
||||
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.constants.*;
|
||||
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
||||
@@ -72,9 +73,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
public JetTypeInfo visitSimpleNameExpression(JetSimpleNameExpression expression, ExpressionTypingContext context) {
|
||||
// TODO : other members
|
||||
// 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);
|
||||
return JetTypeInfo.create(type, context.dataFlowInfo); // TODO : Extensions to this
|
||||
return JetTypeInfo.create(type, typeInfo.getDataFlowInfo()); // TODO : Extensions to this
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -192,37 +194,41 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
public JetTypeInfo visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext context) {
|
||||
JetTypeReference right = expression.getRight();
|
||||
JetType result = null;
|
||||
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||
if (right != null) {
|
||||
JetType targetType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, right, context.trace, true);
|
||||
|
||||
boolean tryWithNoExpectedType = true;
|
||||
if (isTypeFlexible(expression.getLeft()) || expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) {
|
||||
TemporaryBindingTrace temporaryTraceWithExpectedType = TemporaryBindingTrace.create(context.trace);
|
||||
boolean success = checkBinaryWithTypeRHS(expression, context.replaceBindingTrace(temporaryTraceWithExpectedType).replaceExpectedType(targetType), targetType);
|
||||
if (success) {
|
||||
ExpressionTypingContext contextWithTemporaryTrace = context.replaceBindingTrace(temporaryTraceWithExpectedType).replaceExpectedType(targetType);
|
||||
JetTypeInfo typeInfo = facade.getTypeInfo(expression.getLeft(), contextWithTemporaryTrace);
|
||||
if (typeInfo.getType() != null && checkBinaryWithTypeRHS(expression, contextWithTemporaryTrace, targetType, typeInfo.getType())) {
|
||||
temporaryTraceWithExpectedType.commit();
|
||||
}
|
||||
else {
|
||||
checkBinaryWithTypeRHS(expression, context.replaceExpectedType(NO_EXPECTED_TYPE), targetType);
|
||||
dataFlowInfo = typeInfo.getDataFlowInfo();
|
||||
tryWithNoExpectedType = false;
|
||||
}
|
||||
}
|
||||
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();
|
||||
result = operationType == JetTokens.AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType;
|
||||
}
|
||||
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) {
|
||||
|
||||
JetType actualType = facade.getTypeInfo(expression.getLeft(), context).getType();
|
||||
if (actualType == null) return false;
|
||||
|
||||
private boolean checkBinaryWithTypeRHS(JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext context, @NotNull JetType targetType, JetType actualType) {
|
||||
JetSimpleNameExpression operationSign = expression.getOperationSign();
|
||||
IElementType operationType = operationSign.getReferencedNameElementType();
|
||||
if (operationType == JetTokens.COLON) {
|
||||
@@ -537,11 +543,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
if (selectorExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||
if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
|
||||
|
||||
context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());
|
||||
|
||||
if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||
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
|
||||
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?
|
||||
if (result != null) {
|
||||
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, result);
|
||||
if (selectorReturnType != null) {
|
||||
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) {
|
||||
@@ -639,34 +647,33 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
|
||||
@NotNull
|
||||
public JetTypeInfo getSelectorReturnTypeInfo(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
|
||||
if (selectorExpression instanceof JetCallExpression) {
|
||||
|
||||
return getCallExpressionType((JetCallExpression) selectorExpression, receiver, callOperationNode, context);
|
||||
return getCallExpressionTypeInfo((JetCallExpression) selectorExpression, receiver, callOperationNode, context);
|
||||
}
|
||||
else if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||
|
||||
return getSimpleNameExpressionType((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
|
||||
return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
|
||||
}
|
||||
else if (selectorExpression instanceof JetQualifiedExpression) {
|
||||
|
||||
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
|
||||
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();
|
||||
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 {
|
||||
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
|
||||
}
|
||||
return null;
|
||||
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JetType getSimpleNameExpressionType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverDescriptor receiver,
|
||||
@NotNull
|
||||
private JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverDescriptor receiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
|
||||
|
||||
boolean[] result = new boolean[1];
|
||||
@@ -675,7 +682,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceBindingTrace(traceForVariable), result);
|
||||
if (result[0]) {
|
||||
traceForVariable.commit();
|
||||
return type;
|
||||
return JetTypeInfo.create(type, context.dataFlowInfo);
|
||||
}
|
||||
|
||||
Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
|
||||
@@ -685,15 +692,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
traceForFunction.commit();
|
||||
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
|
||||
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();
|
||||
return null;
|
||||
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JetType getCallExpressionType(@NotNull JetCallExpression callExpression, @NotNull ReceiverDescriptor receiver,
|
||||
@NotNull
|
||||
private JetTypeInfo getCallExpressionTypeInfo(@NotNull JetCallExpression callExpression, @NotNull ReceiverDescriptor receiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
|
||||
|
||||
boolean[] result = new boolean[1];
|
||||
@@ -709,7 +717,22 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
|
||||
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();
|
||||
@@ -721,11 +744,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
traceForVariable.commit();
|
||||
context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression,
|
||||
type != null ? type : ErrorUtils.createErrorType("")));
|
||||
return null;
|
||||
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||
}
|
||||
}
|
||||
traceForFunction.commit();
|
||||
return null;
|
||||
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||
}
|
||||
|
||||
private static void checkSuper(@NotNull ReceiverDescriptor receiverDescriptor, @NotNull OverloadResolutionResults<? extends CallableDescriptor> results,
|
||||
@@ -743,8 +766,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
@Override
|
||||
public JetTypeInfo visitCallExpression(JetCallExpression expression, ExpressionTypingContext context) {
|
||||
JetType expressionType = getCallExpressionType(expression, NO_RECEIVER, null, context);
|
||||
return DataFlowUtils.checkType(expressionType, expression, context, context.dataFlowInfo);
|
||||
JetTypeInfo expressionTypeInfo = getCallExpressionTypeInfo(expression, NO_RECEIVER, null, context);
|
||||
return DataFlowUtils.checkType(expressionTypeInfo.getType(), expression, context, expressionTypeInfo.getDataFlowInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -784,6 +807,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
if (isKnownToBeNotNull(baseExpression, context)) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -22,17 +22,16 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
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.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.JetTypeInfo;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
/*package*/ interface ExpressionTypingInternals extends ExpressionTypingFacade {
|
||||
|
||||
@Nullable
|
||||
JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context);
|
||||
@NotNull
|
||||
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);
|
||||
|
||||
|
||||
+8
-3
@@ -115,12 +115,17 @@ public class ExpressionTypingServices {
|
||||
return ErrorUtils.createErrorType("Type for " + expression.getText());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
|
||||
@NotNull
|
||||
public JetTypeInfo getTypeInfo(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
|
||||
ExpressionTypingContext context = ExpressionTypingContext.newContext(
|
||||
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) {
|
||||
|
||||
+12
-6
@@ -69,8 +69,8 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
|
||||
return basic.getSelectorReturnType(receiver, callOperationNode, selectorExpression, context);
|
||||
public JetTypeInfo getSelectorReturnTypeInfo(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
|
||||
return basic.getSelectorReturnTypeInfo(receiver, callOperationNode, selectorExpression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -115,8 +115,11 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
|
||||
@NotNull
|
||||
private JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
|
||||
if (context.trace.get(BindingContext.PROCESSED, expression)) {
|
||||
return JetTypeInfo.create(context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression),
|
||||
context.dataFlowInfo);
|
||||
DataFlowInfo dataFlowInfo = context.trace.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression);
|
||||
if (dataFlowInfo == null) {
|
||||
dataFlowInfo = context.dataFlowInfo;
|
||||
}
|
||||
return JetTypeInfo.create(context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression), dataFlowInfo);
|
||||
}
|
||||
JetTypeInfo result;
|
||||
try {
|
||||
@@ -128,7 +131,7 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
|
||||
}
|
||||
|
||||
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) {
|
||||
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.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();
|
||||
if (decomposerExpression != null) {
|
||||
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) {
|
||||
result.set(checkPatternType(pattern.getArgumentList(), selectorReturnType == null
|
||||
|
||||
@@ -6,8 +6,8 @@ fun foo() {
|
||||
bar(<!TYPE_MISMATCH!>x<!>)
|
||||
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||
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) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) else bar(x!!)
|
||||
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!>!!<!>)
|
||||
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 b : Int? = null
|
||||
a!! : Int
|
||||
a!! + 2
|
||||
a!!.plus(2)
|
||||
a!!.plus(b!!)
|
||||
2.plus(b!!)
|
||||
2 + b!!
|
||||
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!> + 2
|
||||
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.plus(2)
|
||||
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.plus(b!!)
|
||||
2.plus(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||
2 + b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
||||
|
||||
val c = 1
|
||||
c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
||||
@@ -30,6 +30,6 @@ fun main(args : Array<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
val <!UNUSED_VARIABLE!>f<!> : String = <!TYPE_MISMATCH!>a!!<!>
|
||||
<!TYPE_MISMATCH!>a!!<!> : String
|
||||
val <!UNUSED_VARIABLE!>f<!> : String = <!TYPE_MISMATCH!>a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!><!>
|
||||
<!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