resolve argument of 'if' call
with right data flow info
This commit is contained in:
@@ -29,9 +29,13 @@ import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionDebugInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionResultsHandler;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
|
||||
@@ -271,14 +275,14 @@ public class CallResolver {
|
||||
@Nullable TracingStrategy tracing,
|
||||
@NotNull JetReferenceExpression reference,
|
||||
@NotNull ResolutionContext<?> context,
|
||||
@NotNull CallableDescriptor candidate
|
||||
@NotNull ResolutionCandidate<CallableDescriptor> candidate,
|
||||
@Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
|
||||
) {
|
||||
Collection<ResolutionCandidate<CallableDescriptor>> resolutionCandidates = Lists.newArrayList();
|
||||
resolutionCandidates.add(ResolutionCandidate.create(candidate, null));
|
||||
BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(context, call, CheckValueArgumentsMode.ENABLED);
|
||||
BasicCallResolutionContext basicCallResolutionContext =
|
||||
BasicCallResolutionContext.create(context, call, CheckValueArgumentsMode.ENABLED, dataFlowInfoForArguments);
|
||||
|
||||
List<ResolutionTask<CallableDescriptor, FunctionDescriptor>> tasks = TaskPrioritizer
|
||||
.computePrioritizedTasksFromCandidates(basicCallResolutionContext, reference, resolutionCandidates, tracing);
|
||||
.computePrioritizedTasksFromCandidates(basicCallResolutionContext, reference, Collections.singleton(candidate), tracing);
|
||||
return doResolveCallOrGetCachedResults(ResolutionResultsCache.FUNCTION_MEMBER_TYPE, basicCallResolutionContext, tasks,
|
||||
CallTransformer.FUNCTION_CALL_TRANSFORMER, reference);
|
||||
}
|
||||
|
||||
+42
-2
@@ -28,11 +28,14 @@ import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategyImpl;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
||||
@@ -58,7 +61,9 @@ public class ControlStructureTypingUtils {
|
||||
|
||||
/*package*/ static ResolvedCall<FunctionDescriptor> resolveIfAsCall(
|
||||
@NotNull Call callForIf,
|
||||
@NotNull ExpressionTypingContext context
|
||||
@NotNull ExpressionTypingContext context,
|
||||
@NotNull DataFlowInfo thenInfo,
|
||||
@NotNull DataFlowInfo elseInfo
|
||||
) {
|
||||
List<AnnotationDescriptor> noAnnotations = Collections.emptyList();
|
||||
Name specialFunctionName = Name.identifierNoValidate("<SPECIAL-FUNCTION-FOR-IF-RESOLVE>");
|
||||
@@ -89,14 +94,49 @@ public class ControlStructureTypingUtils {
|
||||
|
||||
JetReferenceExpression ifReference = JetPsiFactory.createSimpleName(context.expressionTypingServices.getProject(), "fakeIfCall");
|
||||
TracingStrategy tracingForIf = createTracingForIf(callForIf);
|
||||
MutableDataFlowInfoForArguments dataFlowInfoForArguments = createDataFlowInfoForArgumentsForCall(callForIf, thenInfo, elseInfo);
|
||||
ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(ifFunction, null);
|
||||
OverloadResolutionResults<FunctionDescriptor>
|
||||
results = context.expressionTypingServices.getCallResolver().resolveCallWithKnownCandidate(
|
||||
callForIf, tracingForIf, ifReference, context, ifFunction);
|
||||
callForIf, tracingForIf, ifReference, context, resolutionCandidate, dataFlowInfoForArguments);
|
||||
assert results.isSingleResult() : "Not single result after resolving one known candidate";
|
||||
return results.getResultingCall();
|
||||
}
|
||||
|
||||
private static MutableDataFlowInfoForArguments createDataFlowInfoForArgumentsForCall(
|
||||
final Call callForIf, final DataFlowInfo thenInfo, final DataFlowInfo elseInfo
|
||||
) {
|
||||
return new MutableDataFlowInfoForArguments() {
|
||||
private DataFlowInfo initialDataFlowInfo;
|
||||
|
||||
@Override
|
||||
public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
|
||||
this.initialDataFlowInfo = dataFlowInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
|
||||
if (valueArgument == callForIf.getValueArguments().get(0)) {
|
||||
return thenInfo;
|
||||
}
|
||||
if (valueArgument == callForIf.getValueArguments().get(1)) {
|
||||
return elseInfo;
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataFlowInfo getResultInfo() {
|
||||
return initialDataFlowInfo;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*package*/ static Call createCallForIf(
|
||||
final JetIfExpression ifExpression,
|
||||
|
||||
+9
-9
@@ -22,7 +22,10 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory1;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
@@ -117,15 +120,12 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
if (contextWithExpectedType.expectedType == UNKNOWN_EXPECTED_TYPE) {
|
||||
Call callForIf = ControlStructureTypingUtils.createCallForIf(ifExpression, thenBranch, elseBranch);
|
||||
ResolvedCall<FunctionDescriptor> resultingCall =
|
||||
ControlStructureTypingUtils.resolveIfAsCall(callForIf, contextWithExpectedType);
|
||||
ControlStructureTypingUtils.resolveIfAsCall(callForIf, contextWithExpectedType, thenInfo, elseInfo);
|
||||
|
||||
List<ValueParameterDescriptor> valueParameters = resultingCall.getResultingDescriptor().getValueParameters();
|
||||
ValueParameterDescriptor thenParameter = valueParameters.get(0);
|
||||
ValueParameterDescriptor elseParameter = valueParameters.get(1);
|
||||
//todo correct dataFlowInfo
|
||||
thenTypeInfo = JetTypeInfo.create(thenParameter.getType(), context.dataFlowInfo);
|
||||
elseTypeInfo = JetTypeInfo.create(elseParameter.getType(), context.dataFlowInfo);
|
||||
thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, context.trace.getBindingContext());
|
||||
elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, context.trace.getBindingContext());
|
||||
assert thenTypeInfo != null : "'Then' branch of if expression was not processed: " + ifExpression;
|
||||
assert elseTypeInfo != null : "'Else' branch of if expression was not processed: " + ifExpression;
|
||||
}
|
||||
else {
|
||||
CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION;
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
|
||||
@@ -138,28 +139,35 @@ public class DataFlowUtils {
|
||||
|
||||
@Nullable
|
||||
public static JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context) {
|
||||
if (!noExpectedType(context.expectedType)) {
|
||||
context.trace.record(BindingContext.EXPECTED_EXPRESSION_TYPE, expression, context.expectedType);
|
||||
return checkType(expressionType, expression, context.expectedType, context.dataFlowInfo, context.trace);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression,
|
||||
@NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace
|
||||
) {
|
||||
if (!noExpectedType(expectedType)) {
|
||||
trace.record(BindingContext.EXPECTED_EXPRESSION_TYPE, expression, expectedType);
|
||||
}
|
||||
|
||||
if (expressionType == null || noExpectedType(context.expectedType) ||
|
||||
JetTypeChecker.INSTANCE.isSubtypeOf(expressionType, context.expectedType)) {
|
||||
if (expressionType == null || noExpectedType(expectedType) ||
|
||||
JetTypeChecker.INSTANCE.isSubtypeOf(expressionType, expectedType)) {
|
||||
return expressionType;
|
||||
}
|
||||
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(expression, expressionType, context.trace.getBindingContext());
|
||||
for (JetType possibleType : context.dataFlowInfo.getPossibleTypes(dataFlowValue)) {
|
||||
if (JetTypeChecker.INSTANCE.isSubtypeOf(possibleType, context.expectedType)) {
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(expression, expressionType, trace.getBindingContext());
|
||||
for (JetType possibleType : dataFlowInfo.getPossibleTypes(dataFlowValue)) {
|
||||
if (JetTypeChecker.INSTANCE.isSubtypeOf(possibleType, expectedType)) {
|
||||
if (dataFlowValue.isStableIdentifier()) {
|
||||
context.trace.record(AUTOCAST, expression, possibleType);
|
||||
trace.record(AUTOCAST, expression, possibleType);
|
||||
}
|
||||
else {
|
||||
context.trace.report(AUTOCAST_IMPOSSIBLE.on(expression, possibleType, expression.getText()));
|
||||
trace.report(AUTOCAST_IMPOSSIBLE.on(expression, possibleType, expression.getText()));
|
||||
}
|
||||
return possibleType;
|
||||
}
|
||||
}
|
||||
context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
|
||||
trace.report(TYPE_MISMATCH.on(expression, expectedType, expressionType));
|
||||
return expressionType;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user