Disabled highlighting for variables which are captured in inlined closure.

This commit is contained in:
Evgeny Gerashchenko
2013-04-10 15:41:04 +04:00
parent 6285e5a9f4
commit d502d45772
8 changed files with 188 additions and 13 deletions
@@ -372,8 +372,7 @@ public class CodegenBinding {
public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
return Boolean.TRUE.equals(bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor)) &&
variableDescriptor.isVar();
return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
}
public static boolean hasThis0(BindingContext bindingContext, ClassDescriptor classDescriptor) {
@@ -462,7 +462,7 @@ public class JetFlowInformationProvider {
!DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return;
PseudocodeVariablesData.VariableUseState variableUseState = in.get(variableDescriptor);
if (instruction instanceof WriteValueInstruction) {
if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor)) return;
if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null) return;
JetElement element = ((WriteValueInstruction) instruction).getElement();
if (variableUseState != LAST_READ) {
if (element instanceof JetBinaryExpression &&
@@ -26,14 +26,13 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.DeferredType;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.expressions.CaptureKind;
import org.jetbrains.jet.util.Box;
import org.jetbrains.jet.util.slicedmap.*;
@@ -126,7 +125,7 @@ public interface BindingContext {
WritableSlice<JetExpression, Boolean> PROCESSED = Slices.createSimpleSetSlice();
WritableSlice<JetElement, Boolean> STATEMENT = Slices.createRemovableSetSlice();
WritableSlice<VariableDescriptor, Boolean> CAPTURED_IN_CLOSURE = Slices.createSimpleSetSlice();
WritableSlice<VariableDescriptor, CaptureKind> CAPTURED_IN_CLOSURE = new BasicWritableSlice<VariableDescriptor, CaptureKind>(DO_NOTHING);
// enum DeferredTypeKey {DEFERRED_TYPE_KEY}
// WritableSlice<DeferredTypeKey, Collection<DeferredType>> DEFERRED_TYPES = Slices.createSimpleSlice();
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.types.expressions;
public enum CaptureKind {
NOT_INLINE,
INLINE_ONLY
}
@@ -33,14 +33,15 @@ import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.context.ExpressionPosition;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.context.ExpressionPosition;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -139,12 +140,69 @@ public class ExpressionTypingUtils {
).contains(expression.getNode().getElementType());
}
private static boolean isCapturedInInline(
@NotNull BindingContext context,
@NotNull DeclarationDescriptor scopeContainer,
@NotNull DeclarationDescriptor variableParent
) {
PsiElement scopeDeclaration = BindingContextUtils.descriptorToDeclaration(context, scopeContainer);
if (!(scopeDeclaration instanceof JetFunctionLiteral)) {
return false;
}
PsiElement parent = scopeDeclaration.getParent();
assert parent instanceof JetFunctionLiteralExpression : "parent of JetFunctionLiteral is " + parent;
JetCallExpression callExpression = getCallExpression((JetFunctionLiteralExpression) parent);
if (callExpression == null) {
return false;
}
ResolvedCall<? extends CallableDescriptor> call = context.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression());
if (call == null) {
return false;
}
CallableDescriptor callable = call.getResultingDescriptor();
if (callable instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) callable).isInline()) {
DeclarationDescriptor scopeContainerParent = scopeContainer.getContainingDeclaration();
assert scopeContainerParent != null : "parent is null for " + scopeContainer;
return scopeContainerParent == variableParent || isCapturedInInline(context, scopeContainerParent, variableParent);
}
else {
return false;
}
}
@Nullable
private static JetCallExpression getCallExpression(@NotNull JetFunctionLiteralExpression functionLiteralExpression) {
PsiElement parent = functionLiteralExpression.getParent();
if (parent instanceof JetValueArgument) {
// foo({ ... }) or foo(f = { ... })
PsiElement valueArgumentList = parent.getParent();
assert valueArgumentList instanceof JetValueArgumentList : "parent of value argument is " + valueArgumentList;
if (valueArgumentList.getParent() instanceof JetCallExpression) { // may be argument list of annotation
return (JetCallExpression) valueArgumentList.getParent();
}
}
else if (parent instanceof JetCallExpression) {
// foo { ... }
return (JetCallExpression) parent;
}
return null;
}
public static void checkCapturingInClosure(JetSimpleNameExpression expression, BindingTrace trace, JetScope scope) {
VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true);
if (variable != null) {
DeclarationDescriptor containingDeclaration = variable.getContainingDeclaration();
if (scope.getContainingDeclaration() != containingDeclaration && containingDeclaration instanceof CallableDescriptor) {
trace.record(CAPTURED_IN_CLOSURE, variable);
DeclarationDescriptor variableParent = variable.getContainingDeclaration();
DeclarationDescriptor scopeContainer = scope.getContainingDeclaration();
if (scopeContainer != variableParent && variableParent instanceof CallableDescriptor) {
if (trace.get(CAPTURED_IN_CLOSURE, variable) != CaptureKind.NOT_INLINE) {
boolean inline = isCapturedInInline(trace.getBindingContext(), scopeContainer, variableParent);
trace.record(CAPTURED_IN_CLOSURE, variable, inline ? CaptureKind.INLINE_ONLY : CaptureKind.NOT_INLINE);
}
}
}
}