From c50cf13611f609b84f6cd7f15160f0916415dd6e Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 19 Apr 2016 18:23:44 +0300 Subject: [PATCH] KtExpression.analyzeInContext uses correct context when analyzing return's --- .../resolve/calls/checkers/CallChecker.kt | 19 +++-- .../resolve/calls/checkers/InlineChecker.java | 2 +- .../calls/checkers/coroutineCallChecker.kt | 2 +- .../context/BasicCallResolutionContext.java | 22 ++++-- .../CallCandidateResolutionContext.java | 17 ++-- .../calls/context/CallResolutionContext.java | 7 +- .../calls/context/ResolutionContext.java | 78 ++++++++++++++++--- .../kotlin/resolve/inline/InlineUtil.java | 11 ++- .../BasicExpressionTypingVisitor.java | 4 +- .../ControlStructureTypingVisitor.java | 9 +-- .../expressions/ExpressionTypingContext.java | 19 +++-- .../expressions/ExpressionTypingServices.java | 22 ++++++ .../kotlin/idea/analysis/AnalyzerUtil.kt | 2 +- 13 files changed, 157 insertions(+), 57 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt index 470f0a1bed7..199c04655dd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt @@ -35,15 +35,20 @@ interface CallChecker { } class CallCheckerContext( + val resolutionContext: ResolutionContext<*>, val trace: BindingTrace, - val scope: LexicalScope, - val languageFeatureSettings: LanguageFeatureSettings, - val dataFlowInfo: DataFlowInfo, - val isAnnotationContext: Boolean + val languageFeatureSettings: LanguageFeatureSettings ) { - constructor(c: ResolutionContext<*>, languageFeatureSettings: LanguageFeatureSettings) : this( - c.trace, c.scope, languageFeatureSettings, c.dataFlowInfo, c.isAnnotationContext - ) + val scope: LexicalScope + get() = resolutionContext.scope + + val dataFlowInfo: DataFlowInfo + get() = resolutionContext.dataFlowInfo + + val isAnnotationContext: Boolean + get() = resolutionContext.isAnnotationContext + + constructor(c: ResolutionContext<*>, languageFeatureSettings: LanguageFeatureSettings) : this(c, c.trace, languageFeatureSettings) } // Use this utility to avoid premature computation of deferred return type of a resolved callable descriptor. diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.java index e4f766a9022..6a72cd1814c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.java @@ -285,7 +285,7 @@ class InlineChecker implements CallChecker { ) { if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return; - if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.getTrace())) { + if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.getResolutionContext())) { context.getTrace().report(NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage)); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt index 1c74bba1fb8..aed057e4c32 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt @@ -33,7 +33,7 @@ object CoroutineSuspendCallChecker : CallChecker { val dispatchReceiverOwner = (resolvedCall.dispatchReceiver as? CoroutineReceiverValue)?.declarationDescriptor ?: return val callElement = resolvedCall.call.callElement as KtExpression - if (!InlineUtil.checkNonLocalReturnUsage(dispatchReceiverOwner, callElement, context.trace)) { + if (!InlineUtil.checkNonLocalReturnUsage(dispatchReceiverOwner, callElement, context.resolutionContext)) { context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn)) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/BasicCallResolutionContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/BasicCallResolutionContext.java index 6b83e09ab7e..9a318482a37 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/BasicCallResolutionContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/BasicCallResolutionContext.java @@ -16,9 +16,11 @@ package org.jetbrains.kotlin.resolve.calls.context; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.psi.Call; +import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; @@ -41,10 +43,12 @@ public class BasicCallResolutionContext extends CallResolutionContext expressionContextProvider ) { super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, - dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); + dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, + callPosition, expressionContextProvider); } @NotNull @@ -61,7 +65,7 @@ public class BasicCallResolutionContext extends CallResolutionContext expressionContextProvider ) { return new BasicCallResolutionContext( trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, - dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); + dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, + callPosition, expressionContextProvider); } @NotNull public BasicCallResolutionContext replaceCall(@NotNull Call newCall) { return new BasicCallResolutionContext( trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, - dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); + dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, + callPosition, expressionContextProvider); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallCandidateResolutionContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallCandidateResolutionContext.java index 64809a97151..e4e9c435989 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallCandidateResolutionContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallCandidateResolutionContext.java @@ -16,10 +16,12 @@ package org.jetbrains.kotlin.resolve.calls.context; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.psi.Call; +import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; @@ -54,11 +56,12 @@ public final class CallCandidateResolutionContext boolean isAnnotationContext, boolean isDebuggerContext, boolean collectAllCandidates, - @NotNull CallPosition callPosition + @NotNull CallPosition callPosition, + @NotNull Function1 expressionContextProvider ) { super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, - collectAllCandidates, callPosition); + collectAllCandidates, callPosition, expressionContextProvider); this.candidateCall = candidateCall; this.tracing = tracing; this.candidateResolveMode = candidateResolveMode; @@ -74,7 +77,8 @@ public final class CallCandidateResolutionContext context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache, context.dataFlowInfoForArguments, context.statementFilter, - candidateResolveMode, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, context.callPosition); + candidateResolveMode, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, + context.callPosition, context.expressionContextProvider); } @NotNull @@ -86,7 +90,7 @@ public final class CallCandidateResolutionContext context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache, context.dataFlowInfoForArguments, context.statementFilter, CandidateResolveMode.FULLY, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, - context.callPosition); + context.callPosition, context.expressionContextProvider); } @Override @@ -99,11 +103,12 @@ public final class CallCandidateResolutionContext @NotNull ResolutionResultsCache resolutionResultsCache, @NotNull StatementFilter statementFilter, boolean collectAllCandidates, - @NotNull CallPosition callPosition + @NotNull CallPosition callPosition, + @NotNull Function1 expressionContextProvider ) { return new CallCandidateResolutionContext( candidateCall, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, dataFlowInfoForArguments, statementFilter, - candidateResolveMode, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); + candidateResolveMode, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallResolutionContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallResolutionContext.java index 42315ac0bb4..c5ec7d0840e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallResolutionContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallResolutionContext.java @@ -16,9 +16,11 @@ package org.jetbrains.kotlin.resolve.calls.context; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.psi.Call; +import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl; @@ -50,10 +52,11 @@ public abstract class CallResolutionContext expressionContextProvider ) { super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, - statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); + statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider); this.call = call; this.checkArguments = checkArguments; if (dataFlowInfoForArguments != null) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/ResolutionContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/ResolutionContext.java index 0646a516b70..d75f5b3aa0a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/ResolutionContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/ResolutionContext.java @@ -16,8 +16,12 @@ package org.jetbrains.kotlin.resolve.calls.context; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; @@ -56,6 +60,23 @@ public abstract class ResolutionContext expressionContextProvider; + + public static final Function1 DEFAULT_EXPRESSION_CONTEXT_PROVIDER = new Function1() { + @Override + public KtExpression invoke(KtExpression expression) { + return null; + } + }; + protected ResolutionContext( @NotNull BindingTrace trace, @NotNull LexicalScope scope, @@ -67,7 +88,8 @@ public abstract class ResolutionContext expressionContextProvider ) { this.trace = trace; this.scope = scope; @@ -80,6 +102,7 @@ public abstract class ResolutionContext expressionContextProvider ); @NotNull @@ -104,14 +128,14 @@ public abstract class ResolutionContext expressionContextProvider) { + return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, + collectAllCandidates, callPosition, expressionContextProvider); + } + + @Nullable + public T getContextParentOfType(@NotNull KtExpression expression, @NotNull Class... classes) { + PsiElement current = expression.getParent(); + while (current != null) { + for (Class klass : classes) { + if (klass.isInstance(current)) { + //noinspection unchecked + return (T) current; + } + } + + if (current instanceof PsiFile) return null; + + if (current instanceof KtExpression) { + KtExpression context = expressionContextProvider.invoke((KtExpression) current); + if (context != null) { + current = context; + continue; + } + } + + current = current.getParent(); + } + return null; } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java index 8991f71a8b0..3ba055b2a24 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.resolve.inline; import com.intellij.psi.PsiElement; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.FunctionTypesKt; @@ -25,9 +24,9 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; +import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext; import org.jetbrains.kotlin.resolve.calls.model.ArgumentMapping; import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; @@ -81,19 +80,19 @@ public class InlineUtil { public static boolean checkNonLocalReturnUsage( @NotNull DeclarationDescriptor fromFunction, @NotNull KtExpression startExpression, - @NotNull BindingTrace trace + @NotNull ResolutionContext context ) { - PsiElement containingFunction = PsiTreeUtil.getParentOfType(startExpression, KtClassOrObject.class, KtDeclarationWithBody.class); + PsiElement containingFunction = context.getContextParentOfType(startExpression, KtClassOrObject.class, KtDeclarationWithBody.class); if (containingFunction == null) { return false; } - DeclarationDescriptor containingFunctionDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction); + DeclarationDescriptor containingFunctionDescriptor = context.trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction); if (containingFunctionDescriptor == null) { return false; } - BindingContext bindingContext = trace.getBindingContext(); + BindingContext bindingContext = context.trace.getBindingContext(); while (canBeInlineArgument(containingFunction) && fromFunction != containingFunctionDescriptor) { if (!isInlinedArgument((KtFunction) containingFunction, bindingContext, true)) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 74c323bbde7..bedfbdf935e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -909,9 +909,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (resolvedCall != null) { // Call must be validated with the actual, not temporary trace in order to report operator diagnostic // Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace - CallCheckerContext callCheckerContext = new CallCheckerContext( - trace, context.scope, components.languageFeatureSettings, context.dataFlowInfo, context.isAnnotationContext - ); + CallCheckerContext callCheckerContext = new CallCheckerContext(context, trace, components.languageFeatureSettings); for (CallChecker checker : components.callCheckers) { checker.check(resolvedCall, expression, callCheckerContext); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java index 13d84e543ed..f47cc6f81b1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.types.expressions; import com.google.common.collect.Lists; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; @@ -555,7 +554,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { KotlinType expectedType = NO_EXPECTED_TYPE; KotlinType resultType = components.builtIns.getNothingType(); - KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtDeclaration.class); + KtDeclaration parentDeclaration = context.getContextParentOfType(expression, KtDeclaration.class); if (parentDeclaration instanceof KtParameter) { // In a default value for parameter @@ -565,7 +564,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (expression.getTargetLabel() == null) { while (parentDeclaration instanceof KtDestructuringDeclaration) { //TODO: It's hacking fix for KT-5100: Strange "Return is not allowed here" for multi-declaration initializer with elvis expression - parentDeclaration = PsiTreeUtil.getParentOfType(parentDeclaration, KtDeclaration.class); + parentDeclaration = context.getContextParentOfType(parentDeclaration, KtDeclaration.class); } // Parent declaration can be null in code fragments or in some bad error expressions @@ -576,7 +575,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { FunctionDescriptor containingFunctionDescriptor = containingFunInfo.getFirst(); if (containingFunctionDescriptor != null) { - if (!InlineUtil.checkNonLocalReturnUsage(containingFunctionDescriptor, expression, context.trace) || + if (!InlineUtil.checkNonLocalReturnUsage(containingFunctionDescriptor, expression, context) || isClassInitializer(containingFunInfo)) { // Unqualified, in a function literal context.trace.report(RETURN_NOT_ALLOWED.on(expression)); @@ -595,7 +594,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement); if (functionDescriptor != null) { expectedType = getFunctionExpectedReturnType(functionDescriptor, labelTargetElement, context); - if (!InlineUtil.checkNonLocalReturnUsage(functionDescriptor, expression, context.trace)) { + if (!InlineUtil.checkNonLocalReturnUsage(functionDescriptor, expression, context)) { // Qualified, non-local context.trace.report(RETURN_NOT_ALLOWED.on(expression)); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingContext.java index 6c956bc186c..eb5dad38798 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingContext.java @@ -16,7 +16,9 @@ package org.jetbrains.kotlin.types.expressions; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.calls.context.*; @@ -45,7 +47,7 @@ public class ExpressionTypingContext extends ResolutionContext expressionContextProvider ) { super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, - statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); + statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider); } @Override @@ -101,10 +104,12 @@ public class ExpressionTypingContext extends ResolutionContext expressionContextProvider ) { return new ExpressionTypingContext(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, - statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); + statementFilter, isAnnotationContext, isDebuggerContext, + collectAllCandidates, callPosition, expressionContextProvider); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java index f2a631430f2..b092c59282d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.types.expressions; import com.intellij.psi.tree.IElementType; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; @@ -91,10 +92,31 @@ public class ExpressionTypingServices { @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace, boolean isStatement + ) { + return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace, isStatement, expression); + } + + @NotNull + public KotlinTypeInfo getTypeInfo( + @NotNull LexicalScope scope, + @NotNull final KtExpression expression, + @NotNull KotlinType expectedType, + @NotNull DataFlowInfo dataFlowInfo, + @NotNull BindingTrace trace, + boolean isStatement, + @NotNull final KtExpression contextExpression ) { ExpressionTypingContext context = ExpressionTypingContext.newContext( trace, scope, dataFlowInfo, expectedType ); + if (contextExpression != expression) { + context = context.replaceExpressionContextProvider(new Function1() { + @Override + public KtExpression invoke(KtExpression arg) { + return arg == expression ? contextExpression : null; + } + }); + } return expressionTypingFacade.getTypeInfo(expression, context, isStatement); } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/analysis/AnalyzerUtil.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/analysis/AnalyzerUtil.kt index fa00efa348a..be56a4d615f 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/analysis/AnalyzerUtil.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/analysis/AnalyzerUtil.kt @@ -40,7 +40,7 @@ import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor ): KotlinTypeInfo { PreliminaryDeclarationVisitor.createForExpression(this, trace) return contextExpression.getResolutionFacade().frontendService() - .getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement) + .getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement, contextExpression) } @JvmOverloads fun KtExpression.analyzeInContext(