001/* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.jetbrains.jet.lang.types.expressions; 018 019import com.intellij.psi.PsiElement; 020import com.intellij.util.containers.Stack; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.descriptors.*; 024import org.jetbrains.jet.lang.psi.*; 025import org.jetbrains.jet.lang.resolve.BindingContext; 026import org.jetbrains.jet.lang.resolve.BindingContextUtils; 027import org.jetbrains.jet.lang.resolve.DescriptorResolver; 028import org.jetbrains.jet.lang.resolve.name.LabelName; 029 030import java.util.Collection; 031import java.util.HashMap; 032import java.util.Iterator; 033import java.util.Map; 034 035import static org.jetbrains.jet.lang.diagnostics.Errors.LABEL_NAME_CLASH; 036import static org.jetbrains.jet.lang.diagnostics.Errors.UNRESOLVED_REFERENCE; 037import static org.jetbrains.jet.lang.resolve.BindingContext.LABEL_TARGET; 038import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; 039 040public class LabelResolver { 041 042 private final Map<LabelName, Stack<JetElement>> labeledElements = new HashMap<LabelName, Stack<JetElement>>(); 043 044 public LabelResolver() {} 045 046 public void enterLabeledElement(@NotNull LabelName labelName, @NotNull JetExpression labeledExpression) { 047 JetExpression cacheExpression = getCachingExpression(labeledExpression); 048 if (cacheExpression != null) { 049 Stack<JetElement> stack = labeledElements.get(labelName); 050 if (stack == null) { 051 stack = new Stack<JetElement>(); 052 labeledElements.put(labelName, stack); 053 } 054 stack.push(cacheExpression); 055 } 056 } 057 058 public void exitLabeledElement(@NotNull JetExpression expression) { 059 JetExpression cacheExpression = getCachingExpression(expression); 060 061 // TODO : really suboptimal 062 for (Iterator<Map.Entry<LabelName,Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) { 063 Map.Entry<LabelName, Stack<JetElement>> entry = mapIter.next(); 064 Stack<JetElement> stack = entry.getValue(); 065 for (Iterator<JetElement> stackIter = stack.iterator(); stackIter.hasNext(); ) { 066 JetElement recorded = stackIter.next(); 067 if (recorded == cacheExpression) { 068 stackIter.remove(); 069 } 070 } 071 if (stack.isEmpty()) { 072 mapIter.remove(); 073 } 074 } 075 } 076 077 @NotNull 078 private JetExpression getCachingExpression(@NotNull JetExpression labeledExpression) { 079 JetExpression expression = JetPsiUtil.deparenthesizeWithNoTypeResolution(labeledExpression); 080 if (expression instanceof JetFunctionLiteralExpression) { 081 expression = ((JetFunctionLiteralExpression) expression).getFunctionLiteral(); 082 } 083 return expression; 084 } 085 086 @Nullable 087 private JetElement resolveControlLabel(@NotNull LabelName labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, ExpressionTypingContext context) { 088 Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName); 089 int size = declarationsByLabel.size(); 090 091 if (size == 1) { 092 DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next(); 093 JetElement element; 094 if (declarationDescriptor instanceof FunctionDescriptor || declarationDescriptor instanceof ClassDescriptor) { 095 element = (JetElement) BindingContextUtils.descriptorToDeclaration(context.trace.getBindingContext(), declarationDescriptor); 096 } 097 else { 098 throw new UnsupportedOperationException(declarationDescriptor.getClass().toString()); // TODO 099 } 100 context.trace.record(LABEL_TARGET, labelExpression, element); 101 return element; 102 } 103 else if (size == 0) { 104 return resolveNamedLabel(labelName, labelExpression, reportUnresolved, context); 105 } 106 BindingContextUtils.reportAmbiguousLabel(context.trace, labelExpression, declarationsByLabel); 107 return null; 108 } 109 110 @Nullable 111 public JetElement resolveLabel(JetLabelQualifiedExpression expression, ExpressionTypingContext context) { 112 JetSimpleNameExpression labelElement = expression.getTargetLabel(); 113 if (labelElement != null) { 114 LabelName labelName = new LabelName(expression.getLabelName()); 115 return resolveControlLabel(labelName, labelElement, true, context); 116 } 117 return null; 118 } 119 120 private JetElement resolveNamedLabel(@NotNull LabelName labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, ExpressionTypingContext context) { 121 Stack<JetElement> stack = labeledElements.get(labelName); 122 if (stack == null || stack.isEmpty()) { 123 if (reportUnresolved) { 124 context.trace.report(UNRESOLVED_REFERENCE.on(labelExpression, labelExpression)); 125 } 126 return null; 127 } 128 else if (stack.size() > 1) { 129 context.trace.report(LABEL_NAME_CLASH.on(labelExpression)); 130 } 131 132 JetElement result = stack.peek(); 133 context.trace.record(LABEL_TARGET, labelExpression, result); 134 return result; 135 } 136 137 public LabeledReceiverResolutionResult resolveThisLabel(JetReferenceExpression thisReference, JetSimpleNameExpression targetLabel, 138 ExpressionTypingContext context, LabelName labelName) { 139 Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName); 140 int size = declarationsByLabel.size(); 141 assert targetLabel != null; 142 if (size == 1) { 143 DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next(); 144 ReceiverParameterDescriptor thisReceiver; 145 if (declarationDescriptor instanceof ClassDescriptor) { 146 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; 147 thisReceiver = classDescriptor.getThisAsReceiverParameter(); 148 } 149 else if (declarationDescriptor instanceof FunctionDescriptor) { 150 FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; 151 thisReceiver = functionDescriptor.getReceiverParameter(); 152 } 153 else if (declarationDescriptor instanceof PropertyDescriptor) { 154 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) declarationDescriptor; 155 thisReceiver = propertyDescriptor.getReceiverParameter(); 156 } 157 else { 158 throw new UnsupportedOperationException("Unsupported descriptor: " + declarationDescriptor); // TODO 159 } 160 PsiElement element = BindingContextUtils.descriptorToDeclaration(context.trace.getBindingContext(), declarationDescriptor); 161 assert element != null : "No PSI element for descriptor: " + declarationDescriptor; 162 context.trace.record(LABEL_TARGET, targetLabel, element); 163 context.trace.record(REFERENCE_TARGET, thisReference, declarationDescriptor); 164 165 if (declarationDescriptor instanceof ClassDescriptor) { 166 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; 167 if (!DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, targetLabel, classDescriptor)) { 168 return LabeledReceiverResolutionResult.labelResolutionFailed(); 169 } 170 } 171 172 return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver); 173 } 174 else if (size == 0) { 175 JetElement element = resolveNamedLabel(labelName, targetLabel, false, context); 176 if (element instanceof JetFunctionLiteral) { 177 DeclarationDescriptor declarationDescriptor = 178 context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); 179 if (declarationDescriptor instanceof FunctionDescriptor) { 180 ReceiverParameterDescriptor thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiverParameter(); 181 if (thisReceiver != null) { 182 context.trace.record(LABEL_TARGET, targetLabel, element); 183 context.trace.record(REFERENCE_TARGET, thisReference, declarationDescriptor); 184 } 185 return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver); 186 } 187 else { 188 context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel, targetLabel)); 189 } 190 } 191 else { 192 context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel, targetLabel)); 193 } 194 } 195 else { 196 BindingContextUtils.reportAmbiguousLabel(context.trace, targetLabel, declarationsByLabel); 197 } 198 return LabeledReceiverResolutionResult.labelResolutionFailed(); 199 } 200 201 public static final class LabeledReceiverResolutionResult { 202 public static LabeledReceiverResolutionResult labelResolutionSuccess(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) { 203 if (receiverParameterDescriptor == null) { 204 return new LabeledReceiverResolutionResult(Code.NO_THIS, null); 205 } 206 return new LabeledReceiverResolutionResult(Code.SUCCESS, receiverParameterDescriptor); 207 } 208 209 public static LabeledReceiverResolutionResult labelResolutionFailed() { 210 return new LabeledReceiverResolutionResult(Code.LABEL_RESOLUTION_ERROR, null); 211 } 212 213 public enum Code { 214 LABEL_RESOLUTION_ERROR, 215 NO_THIS, 216 SUCCESS 217 } 218 219 private final Code code; 220 private final ReceiverParameterDescriptor receiverParameterDescriptor; 221 222 private LabeledReceiverResolutionResult( 223 Code code, 224 ReceiverParameterDescriptor receiverParameterDescriptor 225 ) { 226 this.code = code; 227 this.receiverParameterDescriptor = receiverParameterDescriptor; 228 } 229 230 public Code getCode() { 231 return code; 232 } 233 234 public boolean success() { 235 return code == Code.SUCCESS; 236 } 237 238 public ReceiverParameterDescriptor getReceiverParameterDescriptor() { 239 assert success() : "Don't try to obtain the receiver when resolution failed with " + code; 240 return receiverParameterDescriptor; 241 } 242 } 243}