From f3f2bf51235290e43782c2d30145094efa6841fe Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 12 May 2014 19:04:02 +0400 Subject: [PATCH] Removed cache for labeled elements Resolve labels on the fly --- .../jetbrains/jet/lang/psi/JetPsiUtil.java | 8 ++ .../BasicExpressionTypingVisitor.java | 7 +- .../ClosureExpressionsTypingVisitor.java | 44 -------- .../lang/types/expressions/LabelResolver.java | 100 +++++++++++------- 4 files changed, 73 insertions(+), 86 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 01c66436793..842e8b8495b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -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); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 468111d1c06..65077332825 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java index 5f88cc0a6b6..17189ad0565 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java @@ -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, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java index c4922868a84..f6b7fc620d2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java @@ -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> labeledElements = new HashMap>(); - private LabelResolver() {} - public void enterLabeledElement(@NotNull Name labelName, @NotNull JetExpression labeledExpression) { - JetExpression cacheExpression = getCachingExpression(labeledExpression); - if (cacheExpression != null) { - Stack stack = labeledElements.get(labelName); - if (stack == null) { - stack = new Stack(); - labeledElements.put(labelName, stack); + @NotNull + private List getElementsByLabelName(@NotNull Name labelName, @NotNull JetSimpleNameExpression labelExpression) { + List 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>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) { - Map.Entry> entry = mapIter.next(); - Stack stack = entry.getValue(); - for (Iterator 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 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 stack = labeledElements.get(labelName); - if (stack == null || stack.isEmpty()) { + List 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; }