NI: resolve try catch as synthetic function call (#KT-25435 fixed)
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve;
|
package org.jetbrains.kotlin.resolve;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.intellij.openapi.util.Ref;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import kotlin.annotations.jvm.ReadOnly;
|
import kotlin.annotations.jvm.ReadOnly;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -15,7 +16,6 @@ import org.jetbrains.kotlin.cfg.LeakingThisDescriptor;
|
|||||||
import org.jetbrains.kotlin.cfg.TailRecursionKind;
|
import org.jetbrains.kotlin.cfg.TailRecursionKind;
|
||||||
import org.jetbrains.kotlin.contracts.description.InvocationKind;
|
import org.jetbrains.kotlin.contracts.description.InvocationKind;
|
||||||
import org.jetbrains.kotlin.contracts.model.Computation;
|
import org.jetbrains.kotlin.contracts.model.Computation;
|
||||||
import org.jetbrains.kotlin.contracts.model.Functor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
@@ -264,6 +264,8 @@ public interface BindingContext {
|
|||||||
|
|
||||||
WritableSlice<KtExpression, PrimitiveNumericComparisonInfo> PRIMITIVE_NUMERIC_COMPARISON_INFO = Slices.createSimpleSlice();
|
WritableSlice<KtExpression, PrimitiveNumericComparisonInfo> PRIMITIVE_NUMERIC_COMPARISON_INFO = Slices.createSimpleSlice();
|
||||||
|
|
||||||
|
WritableSlice<KtExpression, Ref<VariableDescriptor>> NEW_INFERENCE_CATCH_EXCEPTION_PARAMETER = Slices.createSimpleSlice();
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
@Deprecated // This field is needed only for the side effects of its initializer
|
@Deprecated // This field is needed only for the side effects of its initializer
|
||||||
Void _static_initializer = BasicWritableSlice.initSliceDebugNames(BindingContext.class);
|
Void _static_initializer = BasicWritableSlice.initSliceDebugNames(BindingContext.class);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
|
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext.NEW_INFERENCE_CATCH_EXCEPTION_PARAMETER
|
||||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||||
import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver
|
import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver
|
||||||
@@ -40,9 +41,7 @@ import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
|||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.*
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.expressions.*
|
import org.jetbrains.kotlin.types.expressions.*
|
||||||
@@ -632,6 +631,7 @@ class PSICallResolver(
|
|||||||
|
|
||||||
val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT)
|
val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT)
|
||||||
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
|
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
|
||||||
|
.expandContextForCatchClause(ktExpression)
|
||||||
|
|
||||||
if (ktExpression is KtCallableReferenceExpression) {
|
if (ktExpression is KtCallableReferenceExpression) {
|
||||||
checkNoSpread(outerCallContext, valueArgument)
|
checkNoSpread(outerCallContext, valueArgument)
|
||||||
@@ -683,4 +683,20 @@ class PSICallResolver(
|
|||||||
val typeInfo = expressionTypingServices.getTypeInfo(argumentExpression, context)
|
val typeInfo = expressionTypingServices.getTypeInfo(argumentExpression, context)
|
||||||
return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument
|
return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun BasicCallResolutionContext.expandContextForCatchClause(ktExpression: Any): BasicCallResolutionContext {
|
||||||
|
if (ktExpression !is KtExpression) return this
|
||||||
|
|
||||||
|
val variableDescriptorHolder = trace.bindingContext[NEW_INFERENCE_CATCH_EXCEPTION_PARAMETER, ktExpression] ?: return this
|
||||||
|
val variableDescriptor = variableDescriptorHolder.get() ?: return this
|
||||||
|
variableDescriptorHolder.set(null)
|
||||||
|
|
||||||
|
val redeclarationChecker = expressionTypingServices.createLocalRedeclarationChecker(trace)
|
||||||
|
|
||||||
|
val catchScope = with(scope) {
|
||||||
|
LexicalWritableScope(this, ownerDescriptor, false, redeclarationChecker, LexicalScopeKind.CATCH)
|
||||||
|
}
|
||||||
|
catchScope.addVariableDescriptor(variableDescriptor)
|
||||||
|
return replaceScope(catchScope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-1
@@ -22,6 +22,7 @@ import com.intellij.lang.ASTNode;
|
|||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.util.Ref;
|
import com.intellij.openapi.util.Ref;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import kotlin.Pair;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
|
|||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallResolver;
|
import org.jetbrains.kotlin.resolve.calls.CallResolver;
|
||||||
@@ -67,7 +69,7 @@ public class ControlStructureTypingUtils {
|
|||||||
private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class);
|
private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class);
|
||||||
|
|
||||||
public enum ResolveConstruct {
|
public enum ResolveConstruct {
|
||||||
IF("if"), ELVIS("elvis"), EXCL_EXCL("ExclExcl"), WHEN("when");
|
IF("if"), ELVIS("elvis"), EXCL_EXCL("ExclExcl"), WHEN("when"), TRY("try");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final Name specialFunctionName;
|
private final Name specialFunctionName;
|
||||||
@@ -116,6 +118,39 @@ public class ControlStructureTypingUtils {
|
|||||||
) {
|
) {
|
||||||
SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
|
SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
|
||||||
construct, argumentNames, isArgumentNullable);
|
construct, argumentNames, isArgumentNullable);
|
||||||
|
return resolveSpecialConstructionAsCall(call, function, construct, context, dataFlowInfoForArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ ResolvedCall<FunctionDescriptor> resolveTryAsCall(
|
||||||
|
@NotNull Call call,
|
||||||
|
@NotNull KtTryExpression tryExpression,
|
||||||
|
@NotNull List<Pair<KtExpression, VariableDescriptor>> catchedExceptions,
|
||||||
|
@NotNull ExpressionTypingContext context,
|
||||||
|
@Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
|
||||||
|
) {
|
||||||
|
List<String> argumentNames = Lists.newArrayList("tryBlock");
|
||||||
|
List<Boolean> argumentsNullability = Lists.newArrayList(false);
|
||||||
|
for (int i = 0; i < tryExpression.getCatchClauses().size(); i++) {
|
||||||
|
argumentNames.add("catchBlock" + i);
|
||||||
|
argumentsNullability.add(false);
|
||||||
|
}
|
||||||
|
SimpleFunctionDescriptorImpl function =
|
||||||
|
createFunctionDescriptorForSpecialConstruction(ResolveConstruct.TRY, argumentNames, argumentsNullability);
|
||||||
|
for (Pair<KtExpression, VariableDescriptor> descriptorPair : catchedExceptions) {
|
||||||
|
KtExpression catchBlock = descriptorPair.getFirst();
|
||||||
|
VariableDescriptor catchedExceptionDescriptor = descriptorPair.getSecond();
|
||||||
|
context.trace.record(BindingContext.NEW_INFERENCE_CATCH_EXCEPTION_PARAMETER, catchBlock, Ref.create(catchedExceptionDescriptor));
|
||||||
|
}
|
||||||
|
return resolveSpecialConstructionAsCall(call, function, ResolveConstruct.TRY, context, dataFlowInfoForArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
|
||||||
|
@NotNull Call call,
|
||||||
|
@NotNull SimpleFunctionDescriptorImpl function,
|
||||||
|
@NotNull ResolveConstruct construct,
|
||||||
|
@NotNull ExpressionTypingContext context,
|
||||||
|
@Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
|
||||||
|
) {
|
||||||
TracingStrategy tracing = createTracingForSpecialConstruction(call, construct.getName(), context);
|
TracingStrategy tracing = createTracingForSpecialConstruction(call, construct.getName(), context);
|
||||||
TypeSubstitutor knownTypeParameterSubstitutor = createKnownTypeParameterSubstitutorForSpecialCall(construct, function, context.expectedType, context.languageVersionSettings);
|
TypeSubstitutor knownTypeParameterSubstitutor = createKnownTypeParameterSubstitutorForSpecialCall(construct, function, context.expectedType, context.languageVersionSettings);
|
||||||
ResolutionCandidate<FunctionDescriptor> resolutionCandidate =
|
ResolutionCandidate<FunctionDescriptor> resolutionCandidate =
|
||||||
@@ -252,6 +287,20 @@ public class ControlStructureTypingUtils {
|
|||||||
return createIndependentDataFlowInfoForArgumentsForCall(subjectDataFlowInfo, dataFlowInfoForArgumentsMap);
|
return createIndependentDataFlowInfoForArgumentsForCall(subjectDataFlowInfo, dataFlowInfoForArgumentsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MutableDataFlowInfoForArguments createDataFlowInfoForArgumentsOfTryCall(
|
||||||
|
@NotNull Call callForTry,
|
||||||
|
@NotNull DataFlowInfo dataFlowInfoBeforeTry,
|
||||||
|
@NotNull DataFlowInfo dataFlowInfoAfterTry
|
||||||
|
) {
|
||||||
|
Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap = new HashMap<>();
|
||||||
|
List<? extends ValueArgument> valueArguments = callForTry.getValueArguments();
|
||||||
|
dataFlowInfoForArgumentsMap.put(valueArguments.get(0), dataFlowInfoBeforeTry);
|
||||||
|
for (int i = 1; i < valueArguments.size(); i++) {
|
||||||
|
dataFlowInfoForArgumentsMap.put(valueArguments.get(i), dataFlowInfoAfterTry);
|
||||||
|
}
|
||||||
|
return createIndependentDataFlowInfoForArgumentsForCall(dataFlowInfoBeforeTry, dataFlowInfoForArgumentsMap);
|
||||||
|
}
|
||||||
|
|
||||||
/*package*/ static Call createCallForSpecialConstruction(
|
/*package*/ static Call createCallForSpecialConstruction(
|
||||||
@NotNull KtExpression expression,
|
@NotNull KtExpression expression,
|
||||||
@NotNull KtExpression calleeExpression,
|
@NotNull KtExpression calleeExpression,
|
||||||
|
|||||||
+132
-20
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.types.expressions;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import kotlin.collections.CollectionsKt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
@@ -47,13 +48,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.diagnostics.Errors.*;
|
import static org.jetbrains.kotlin.diagnostics.Errors.*;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||||
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
|
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
|
||||||
import static org.jetbrains.kotlin.types.TypeUtils.*;
|
import static org.jetbrains.kotlin.types.TypeUtils.*;
|
||||||
import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createCallForSpecialConstruction;
|
import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.*;
|
||||||
import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createDataFlowInfoForArgumentsForIfCall;
|
|
||||||
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
|
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
|
||||||
|
|
||||||
public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||||
@@ -489,6 +490,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KotlinTypeInfo visitTryExpression(@NotNull KtTryExpression expression, ExpressionTypingContext typingContext) {
|
public KotlinTypeInfo visitTryExpression(@NotNull KtTryExpression expression, ExpressionTypingContext typingContext) {
|
||||||
|
if (typingContext.languageVersionSettings.supportsFeature(LanguageFeature.NewInference)) {
|
||||||
|
return resolveTryExpressionWithNewInference(expression, typingContext);
|
||||||
|
}
|
||||||
ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT);
|
ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT);
|
||||||
KtExpression tryBlock = expression.getTryBlock();
|
KtExpression tryBlock = expression.getTryBlock();
|
||||||
List<KtCatchClause> catchClauses = expression.getCatchClauses();
|
List<KtCatchClause> catchClauses = expression.getCatchClauses();
|
||||||
@@ -500,15 +504,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
KtExpression catchBody = catchClause.getCatchBody();
|
KtExpression catchBody = catchClause.getCatchBody();
|
||||||
boolean nothingInCatchBranch = false;
|
boolean nothingInCatchBranch = false;
|
||||||
if (catchParameter != null) {
|
if (catchParameter != null) {
|
||||||
checkCatchParameterDeclaration(catchParameter, context);
|
VariableDescriptor variableDescriptor = resolveAndCheckCatchParameter(catchParameter, context);
|
||||||
|
|
||||||
VariableDescriptor variableDescriptor = components.descriptorResolver.resolveLocalVariableDescriptor(
|
|
||||||
context.scope, catchParameter, context.trace);
|
|
||||||
KotlinType catchParameterType = variableDescriptor.getType();
|
|
||||||
checkCatchParameterType(catchParameter, catchParameterType, context);
|
|
||||||
|
|
||||||
KotlinType throwableType = components.builtIns.getThrowable().getDefaultType();
|
|
||||||
components.dataFlowAnalyzer.checkType(catchParameterType, catchParameter, context.replaceExpectedType(throwableType));
|
|
||||||
if (catchBody != null) {
|
if (catchBody != null) {
|
||||||
LexicalWritableScope catchScope = newWritableScopeImpl(context, LexicalScopeKind.CATCH, components.overloadChecker);
|
LexicalWritableScope catchScope = newWritableScopeImpl(context, LexicalScopeKind.CATCH, components.overloadChecker);
|
||||||
catchScope.addVariableDescriptor(variableDescriptor);
|
catchScope.addVariableDescriptor(variableDescriptor);
|
||||||
@@ -527,15 +524,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KotlinTypeInfo tryResult = facade.getTypeInfo(tryBlock, context);
|
KotlinTypeInfo tryResult = facade.getTypeInfo(tryBlock, context);
|
||||||
ExpressionTypingContext tryOutputContext = context.replaceExpectedType(NO_EXPECTED_TYPE);
|
ExpressionTypingContext tryOutputContext = getCleanedContextFromTryWithAssignmentsToVar(expression, nothingInAllCatchBranches, context);
|
||||||
if (!nothingInAllCatchBranches &&
|
|
||||||
facade.getComponents().languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartCastsAfterTry)) {
|
|
||||||
PreliminaryLoopVisitor tryVisitor = PreliminaryLoopVisitor.visitTryBlock(expression);
|
|
||||||
tryOutputContext = tryOutputContext.replaceDataFlowInfo(
|
|
||||||
tryVisitor.clearDataFlowInfoForAssignedLocalVariables(tryOutputContext.dataFlowInfo,
|
|
||||||
components.languageVersionSettings)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
KotlinTypeInfo result = TypeInfoFactoryKt.noTypeInfo(tryOutputContext);
|
KotlinTypeInfo result = TypeInfoFactoryKt.noTypeInfo(tryOutputContext);
|
||||||
if (finallyBlock != null) {
|
if (finallyBlock != null) {
|
||||||
@@ -557,6 +546,129 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private KotlinTypeInfo resolveTryExpressionWithNewInference(@NotNull KtTryExpression tryExpression, ExpressionTypingContext tryInputContext) {
|
||||||
|
// tryInputContext is an ExpressionTypingContext before try/catch expression
|
||||||
|
|
||||||
|
KtBlockExpression tryBlock = tryExpression.getTryBlock();
|
||||||
|
List<KtCatchClause> catchClauses = tryExpression.getCatchClauses();
|
||||||
|
KtFinallySection finallySection = tryExpression.getFinallyBlock();
|
||||||
|
|
||||||
|
DataFlowInfo dataFlowInfoBeforeTry = tryInputContext.dataFlowInfo;
|
||||||
|
|
||||||
|
List<KtExpression> catchBlocks = Lists.newArrayList();
|
||||||
|
List<kotlin.Pair<KtExpression, VariableDescriptor>> catchClausesBlocksAndParameters = Lists.newArrayList();
|
||||||
|
|
||||||
|
for (KtCatchClause catchClause : catchClauses) {
|
||||||
|
KtParameter catchParameter = catchClause.getCatchParameter();
|
||||||
|
KtExpression catchBody = catchClause.getCatchBody();
|
||||||
|
if (catchParameter != null) {
|
||||||
|
VariableDescriptor variableDescriptor = resolveAndCheckCatchParameter(catchParameter, tryInputContext);
|
||||||
|
if (catchBody != null) {
|
||||||
|
catchBlocks.add(catchBody);
|
||||||
|
catchClausesBlocksAndParameters.add(new kotlin.Pair<>(catchBody, variableDescriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KtBlockExpression finallyBlock = null;
|
||||||
|
if (finallySection != null) {
|
||||||
|
finallyBlock = finallySection.getFinalExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<KtExpression> arguments = Lists.newArrayList(tryBlock);
|
||||||
|
arguments.addAll(catchBlocks);
|
||||||
|
|
||||||
|
Call callForTry = createCallForSpecialConstruction(tryExpression, tryExpression, arguments);
|
||||||
|
|
||||||
|
MutableDataFlowInfoForArguments dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfTryCall(callForTry, dataFlowInfoBeforeTry, dataFlowInfoBeforeTry);
|
||||||
|
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils
|
||||||
|
.resolveTryAsCall(callForTry, tryExpression, catchClausesBlocksAndParameters, tryInputContext, dataFlowInfoForArguments);
|
||||||
|
KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType();
|
||||||
|
|
||||||
|
BindingContext bindingContext = tryInputContext.trace.getBindingContext();
|
||||||
|
|
||||||
|
return processTryBranches(tryExpression, tryBlock, tryInputContext, catchBlocks, finallyBlock, bindingContext, resultType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private KotlinTypeInfo processTryBranches(
|
||||||
|
@NotNull KtTryExpression tryExpression,
|
||||||
|
KtBlockExpression tryBlock,
|
||||||
|
ExpressionTypingContext context,
|
||||||
|
List<KtExpression> catchBlocks,
|
||||||
|
KtBlockExpression finallyBlock,
|
||||||
|
BindingContext bindingContext,
|
||||||
|
KotlinType resultType
|
||||||
|
) {
|
||||||
|
KotlinTypeInfo tryInfo = BindingContextUtils.getRecordedTypeInfo(tryBlock, bindingContext);
|
||||||
|
DataFlowInfo dataFlowInfoAfterTry;
|
||||||
|
if (tryInfo != null) {
|
||||||
|
dataFlowInfoAfterTry = tryInfo.getDataFlowInfo();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dataFlowInfoAfterTry = DataFlowInfo.Companion.getEMPTY();
|
||||||
|
}
|
||||||
|
boolean nothingInAllCatchBranches = isCatchBranchesReturnsNothing(catchBlocks, bindingContext);
|
||||||
|
|
||||||
|
// it is not actually correct way (#KT-28370) of computing context, but it's how was in OI
|
||||||
|
ExpressionTypingContext tryOutputContext = getCleanedContextFromTryWithAssignmentsToVar(tryExpression, nothingInAllCatchBranches, context);
|
||||||
|
|
||||||
|
KotlinTypeInfo result = TypeInfoFactoryKt.createTypeInfo(resultType, tryOutputContext);
|
||||||
|
|
||||||
|
if (finallyBlock != null) {
|
||||||
|
return facade.getTypeInfo(finallyBlock, tryOutputContext).replaceType(resultType);
|
||||||
|
} else if (!nothingInAllCatchBranches || tryInfo == null) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return TypeInfoFactoryKt.createTypeInfo(
|
||||||
|
components.dataFlowAnalyzer.checkType(resultType, tryExpression, tryOutputContext),
|
||||||
|
dataFlowInfoAfterTry
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCatchBranchesReturnsNothing(List<KtExpression> catchBlocks, BindingContext bindingContext) {
|
||||||
|
return CollectionsKt.all(whichCatchBranchesReturnNothing(catchBlocks, bindingContext), it -> it);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Boolean> whichCatchBranchesReturnNothing(List<KtExpression> catchBlocks, BindingContext bindingContext) {
|
||||||
|
return catchBlocks.stream()
|
||||||
|
.map(catchBlock -> BindingContextUtils.getRecordedTypeInfo(catchBlock, bindingContext))
|
||||||
|
.map(catchTypeInfo -> {
|
||||||
|
if (catchTypeInfo == null) return true;
|
||||||
|
KotlinType catchType = catchTypeInfo.getType();
|
||||||
|
return catchType == null || KotlinBuiltIns.isNothing(catchType);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private VariableDescriptor resolveAndCheckCatchParameter(@NotNull KtParameter catchParameter, ExpressionTypingContext context) {
|
||||||
|
checkCatchParameterDeclaration(catchParameter, context);
|
||||||
|
|
||||||
|
VariableDescriptor variableDescriptor = components.descriptorResolver
|
||||||
|
.resolveLocalVariableDescriptor(context.scope, catchParameter, context.trace);
|
||||||
|
KotlinType catchParameterType = variableDescriptor.getType();
|
||||||
|
checkCatchParameterType(catchParameter, catchParameterType, context);
|
||||||
|
KotlinType throwableType = components.builtIns.getThrowable().getDefaultType();
|
||||||
|
components.dataFlowAnalyzer.checkType(catchParameterType, catchParameter, context.replaceExpectedType(throwableType));
|
||||||
|
return variableDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExpressionTypingContext getCleanedContextFromTryWithAssignmentsToVar(
|
||||||
|
KtTryExpression tryExpression,
|
||||||
|
boolean nothingInAllCatchBranches,
|
||||||
|
ExpressionTypingContext context
|
||||||
|
) {
|
||||||
|
context = context.replaceExpectedType(NO_EXPECTED_TYPE);
|
||||||
|
if (!nothingInAllCatchBranches && facade.getComponents().languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartCastsAfterTry)) {
|
||||||
|
PreliminaryLoopVisitor tryVisitor = PreliminaryLoopVisitor.visitTryBlock(tryExpression);
|
||||||
|
context = context.replaceDataFlowInfo(
|
||||||
|
tryVisitor.clearDataFlowInfoForAssignedLocalVariables(context.dataFlowInfo, components.languageVersionSettings)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
private static void checkCatchParameterType(KtParameter catchParameter, KotlinType catchParameterType, ExpressionTypingContext context) {
|
private static void checkCatchParameterType(KtParameter catchParameter, KotlinType catchParameterType, ExpressionTypingContext context) {
|
||||||
TypeParameterDescriptor typeParameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(catchParameterType);
|
TypeParameterDescriptor typeParameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(catchParameterType);
|
||||||
if (typeParameterDescriptor != null) {
|
if (typeParameterDescriptor != null) {
|
||||||
@@ -679,7 +791,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
} else {
|
} else {
|
||||||
KotlinTypeInfo result = facade
|
KotlinTypeInfo result = facade
|
||||||
.getTypeInfo(returnedExpression, context.replaceExpectedType(newInferenceLambdaInfo.getExpectedType())
|
.getTypeInfo(returnedExpression, context.replaceExpectedType(newInferenceLambdaInfo.getExpectedType())
|
||||||
.replaceContextDependency(newInferenceLambdaInfo.getContextDependency()));
|
.replaceContextDependency(newInferenceLambdaInfo.getContextDependency()));
|
||||||
contextInfo = new LambdaContextInfo(result, null, context.scope, context.trace);
|
contextInfo = new LambdaContextInfo(result, null, context.scope, context.trace);
|
||||||
}
|
}
|
||||||
newInferenceLambdaInfo.getReturnStatements().add(new kotlin.Pair<>(expression, contextInfo));
|
newInferenceLambdaInfo.getReturnStatements().add(new kotlin.Pair<>(expression, contextInfo));
|
||||||
|
|||||||
+5
-4
@@ -24,10 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionCallbacksImpl;
|
import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionCallbacksImpl;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
|
import org.jetbrains.kotlin.resolve.scopes.*;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.TraceBasedLocalRedeclarationChecker;
|
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
||||||
@@ -380,4 +377,8 @@ public class ExpressionTypingServices {
|
|||||||
return slice == BindingContext.EXPRESSION_EFFECTS;
|
return slice == BindingContext.EXPRESSION_EFFECTS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LocalRedeclarationChecker createLocalRedeclarationChecker(BindingTrace trace) {
|
||||||
|
return new TraceBasedLocalRedeclarationChecker(trace, expressionTypingComponents.overloadChecker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,15 +14,15 @@ fun foo() : Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun bar() : Int =
|
fun bar() : Int =
|
||||||
try {
|
<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH!>try {
|
||||||
<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>doSmth()<!>
|
<!OI;TYPE_MISMATCH!>doSmth()<!>
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
<!TYPE_MISMATCH!>""<!>
|
<!OI;TYPE_MISMATCH!>""<!>
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
<!UNUSED_EXPRESSION!>""<!>
|
<!UNUSED_EXPRESSION!>""<!>
|
||||||
}
|
}<!>
|
||||||
|
|
||||||
|
|
||||||
fun doSmth() {}
|
fun doSmth() {}
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ class ExcA : Exception()
|
|||||||
class ExcB : Exception()
|
class ExcB : Exception()
|
||||||
|
|
||||||
fun test2() {
|
fun test2() {
|
||||||
val s: String? = try {
|
val s: String? = <!NI;TYPE_MISMATCH!>try {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
catch (e: ExcA) {
|
catch (e: ExcA) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
catch (e: ExcB) {
|
catch (e: ExcB) {
|
||||||
<!CONSTANT_EXPECTED_TYPE_MISMATCH!>10<!>
|
<!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>10<!>
|
||||||
}
|
}<!>
|
||||||
s<!UNSAFE_CALL!>.<!>length
|
s<!UNSAFE_CALL!>.<!>length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ fun test0(): List<Int> = run {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test1(): Map<Int, Int> = <!NI;TYPE_MISMATCH!>run {
|
fun test1(): Map<Int, Int> = run {
|
||||||
<!NI;TYPE_MISMATCH!>try {
|
try {
|
||||||
emptyMap()
|
emptyMap()
|
||||||
} catch (e: ExcA) {
|
} catch (e: ExcA) {
|
||||||
emptyMap()
|
emptyMap()
|
||||||
@@ -22,13 +22,13 @@ fun test1(): Map<Int, Int> = <!NI;TYPE_MISMATCH!>run {
|
|||||||
e.map
|
e.map
|
||||||
} finally {
|
} finally {
|
||||||
<!UNUSED_EXPRESSION!>""<!>
|
<!UNUSED_EXPRESSION!>""<!>
|
||||||
}<!>
|
}
|
||||||
}<!>
|
}
|
||||||
|
|
||||||
fun test2(): Map<Int, Int> = <!NI;TYPE_MISMATCH!>run {
|
fun test2(): Map<Int, Int> = run {
|
||||||
<!NI;TYPE_MISMATCH!>try {
|
<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, NI;TYPE_MISMATCH!>try {
|
||||||
emptyMap()
|
emptyMap()
|
||||||
} catch (e: ExcA) {
|
} catch (e: ExcA) {
|
||||||
<!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>mapOf("" to "")<!>
|
<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>mapOf(<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH!>"" to ""<!>)<!>
|
||||||
}<!>
|
}<!>
|
||||||
}<!>
|
}
|
||||||
Reference in New Issue
Block a user