Removed cache for labeled elements

Resolve labels on the fly
This commit is contained in:
Svetlana Isakova
2014-05-12 19:04:02 +04:00
parent 3bcdbee2bf
commit f3f2bf5123
4 changed files with 73 additions and 86 deletions
@@ -136,6 +136,14 @@ public class JetPsiUtil {
return JetTokens.LABELS.contains(expression.getOperationReference().getReferencedNameElementType());
}
@NotNull
public static String getLabelName(@NotNull JetPrefixExpression expression) {
assert isLabeledExpression(expression);
String labelName = expression.getOperationReference().getReferencedName();
assert labelName.startsWith("@") : "Incorrect label name " + expression.getText();
return labelName.substring(1);
}
@NotNull
public static Name safeName(@Nullable String name) {
return name == null ? SpecialNames.NO_NAME_PROVIDED : Name.identifier(name);
@@ -748,12 +748,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetSimpleNameExpression operationSign = expression.getOperationReference();
assert JetTokens.LABELS.contains(operationSign.getReferencedNameElementType());
String referencedName = operationSign.getReferencedName();
context.labelResolver.enterLabeledElement(Name.identifierForLabel(referencedName.substring(1)), baseExpression);
// TODO : Some processing for the label?
JetTypeInfo typeInfo = facade.getTypeInfo(baseExpression, context, isStatement);
context.labelResolver.exitLabeledElement(baseExpression);
return typeInfo;
return facade.getTypeInfo(baseExpression, context, isStatement);
}
private static boolean isKnownToBeNotNull(JetExpression expression, ExpressionTypingContext context) {
@@ -103,11 +103,6 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
if (bodyExpression == null) return null;
Name callerName = getCallerName(expression);
if (callerName != null) {
context.labelResolver.enterLabeledElement(callerName, expression);
}
JetType expectedType = context.expectedType;
boolean functionTypeExpected = !noExpectedType(expectedType) && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(
expectedType);
@@ -125,48 +120,9 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
return JetTypeInfo.create(resultType, context.dataFlowInfo);
}
if (callerName != null) {
context.labelResolver.exitLabeledElement(expression);
}
return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo);
}
@Nullable
private static Name getCallerName(@NotNull JetFunctionLiteralExpression expression) {
JetCallExpression callExpression = getContainingCallExpression(expression);
if (callExpression == null) return null;
JetExpression calleeExpression = callExpression.getCalleeExpression();
if (calleeExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression;
return nameExpression.getReferencedNameAsName();
}
return null;
}
@Nullable
private static JetCallExpression getContainingCallExpression(JetFunctionLiteralExpression expression) {
PsiElement parent = expression.getParent();
if (parent instanceof JetCallExpression) {
// f {}
return (JetCallExpression) parent;
}
if (parent instanceof JetValueArgument) {
// f ({}) or f(p = {})
JetValueArgument argument = (JetValueArgument) parent;
PsiElement argList = argument.getParent();
if (argList == null) return null;
PsiElement call = argList.getParent();
if (call instanceof JetCallExpression) {
return (JetCallExpression) call;
}
}
return null;
}
@NotNull
private AnonymousFunctionDescriptor createFunctionDescriptor(
@NotNull JetFunctionLiteralExpression expression,
@@ -16,8 +16,8 @@
package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
@@ -28,9 +28,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorResolver;
import org.jetbrains.jet.lang.resolve.name.Name;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.LABEL_NAME_CLASH;
import static org.jetbrains.jet.lang.diagnostics.Errors.UNRESOLVED_REFERENCE;
@@ -44,50 +42,80 @@ public class LabelResolver {
return new LabelResolver();
}
private final Map<Name, Stack<JetElement>> labeledElements = new HashMap<Name, Stack<JetElement>>();
private LabelResolver() {}
public void enterLabeledElement(@NotNull Name labelName, @NotNull JetExpression labeledExpression) {
JetExpression cacheExpression = getCachingExpression(labeledExpression);
if (cacheExpression != null) {
Stack<JetElement> stack = labeledElements.get(labelName);
if (stack == null) {
stack = new Stack<JetElement>();
labeledElements.put(labelName, stack);
@NotNull
private List<JetElement> getElementsByLabelName(@NotNull Name labelName, @NotNull JetSimpleNameExpression labelExpression) {
List<JetElement> elements = Lists.newArrayList();
PsiElement parent = labelExpression.getParent();
while (parent != null) {
Name name = getLabelNameIfAny(parent);
if (name != null && name.equals(labelName)) {
elements.add(getExpressionUnderLabel((JetExpression) parent));
}
stack.push(cacheExpression);
parent = parent.getParent();
}
return elements;
}
public void exitLabeledElement(@NotNull JetExpression expression) {
JetExpression cacheExpression = getCachingExpression(expression);
// TODO : really suboptimal
for (Iterator<Map.Entry<Name,Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) {
Map.Entry<Name, Stack<JetElement>> entry = mapIter.next();
Stack<JetElement> stack = entry.getValue();
for (Iterator<JetElement> stackIter = stack.iterator(); stackIter.hasNext(); ) {
JetElement recorded = stackIter.next();
if (recorded == cacheExpression) {
stackIter.remove();
}
}
if (stack.isEmpty()) {
mapIter.remove();
@Nullable
private Name getLabelNameIfAny(@NotNull PsiElement element) {
if (element instanceof JetPrefixExpression) {
JetPrefixExpression prefixExpression = (JetPrefixExpression) element;
if (JetPsiUtil.isLabeledExpression(prefixExpression)) {
return Name.identifierForLabel(JetPsiUtil.getLabelName(prefixExpression));
}
}
else if (element instanceof JetFunctionLiteralExpression) {
return getCallerName((JetFunctionLiteralExpression) element);
}
return null;
}
@NotNull
private JetExpression getCachingExpression(@NotNull JetExpression labeledExpression) {
JetExpression expression = JetPsiUtil.deparenthesize(labeledExpression);
private JetExpression getExpressionUnderLabel(@NotNull JetExpression labeledExpression) {
JetExpression expression = JetPsiUtil.safeDeparenthesize(labeledExpression, true);
if (expression instanceof JetFunctionLiteralExpression) {
expression = ((JetFunctionLiteralExpression) expression).getFunctionLiteral();
return ((JetFunctionLiteralExpression) expression).getFunctionLiteral();
}
return expression;
}
@Nullable
private Name getCallerName(@NotNull JetFunctionLiteralExpression expression) {
JetCallExpression callExpression = getContainingCallExpression(expression);
if (callExpression == null) return null;
JetExpression calleeExpression = callExpression.getCalleeExpression();
if (calleeExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression;
return nameExpression.getReferencedNameAsName();
}
return null;
}
@Nullable
private JetCallExpression getContainingCallExpression(JetFunctionLiteralExpression expression) {
PsiElement parent = expression.getParent();
if (parent instanceof JetCallExpression) {
// f {}
return (JetCallExpression) parent;
}
if (parent instanceof JetValueArgument) {
// f ({}) or f(p = {})
JetValueArgument argument = (JetValueArgument) parent;
PsiElement argList = argument.getParent();
if (argList == null) return null;
PsiElement call = argList.getParent();
if (call instanceof JetCallExpression) {
return (JetCallExpression) call;
}
}
return null;
}
@Nullable
private JetElement resolveControlLabel(@NotNull Name labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, ExpressionTypingContext context) {
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
@@ -123,18 +151,18 @@ public class LabelResolver {
}
private JetElement resolveNamedLabel(@NotNull Name labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, ExpressionTypingContext context) {
Stack<JetElement> stack = labeledElements.get(labelName);
if (stack == null || stack.isEmpty()) {
List<JetElement> list = getElementsByLabelName(labelName, labelExpression);
if (list.isEmpty()) {
if (reportUnresolved) {
context.trace.report(UNRESOLVED_REFERENCE.on(labelExpression, labelExpression));
}
return null;
}
else if (stack.size() > 1) {
else if (list.size() > 1) {
context.trace.report(LABEL_NAME_CLASH.on(labelExpression));
}
JetElement result = stack.peek();
JetElement result = list.get(0);
context.trace.record(LABEL_TARGET, labelExpression, result);
return result;
}