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.google.common.collect.Sets; 020import com.intellij.psi.tree.IElementType; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.descriptors.*; 024import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorUtil; 025import org.jetbrains.jet.lang.diagnostics.Errors; 026import org.jetbrains.jet.lang.psi.*; 027import org.jetbrains.jet.lang.resolve.BindingContext; 028import org.jetbrains.jet.lang.resolve.ModifiersChecker; 029import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; 030import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; 031import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; 032import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 033import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; 034import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil; 035import org.jetbrains.jet.lang.resolve.name.Name; 036import org.jetbrains.jet.lang.resolve.scopes.JetScope; 037import org.jetbrains.jet.lang.resolve.scopes.WritableScope; 038import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; 039import org.jetbrains.jet.lang.types.JetType; 040import org.jetbrains.jet.lang.types.JetTypeInfo; 041import org.jetbrains.jet.lang.types.TypeUtils; 042import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 043import org.jetbrains.jet.lexer.JetTokens; 044 045import java.util.Collection; 046 047import static org.jetbrains.jet.lang.diagnostics.Errors.*; 048import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET; 049import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT; 050 051@SuppressWarnings("SuspiciousMethodCalls") 052public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisitor { 053 private final WritableScope scope; 054 private final BasicExpressionTypingVisitor basic; 055 private final ControlStructureTypingVisitor controlStructures; 056 private final PatternMatchingTypingVisitor patterns; 057 058 public ExpressionTypingVisitorForStatements( 059 @NotNull ExpressionTypingInternals facade, 060 @NotNull WritableScope scope, 061 BasicExpressionTypingVisitor basic, 062 @NotNull ControlStructureTypingVisitor controlStructures, 063 @NotNull PatternMatchingTypingVisitor patterns) { 064 super(facade); 065 this.scope = scope; 066 this.basic = basic; 067 this.controlStructures = controlStructures; 068 this.patterns = patterns; 069 } 070 071 @Nullable 072 private static JetType checkAssignmentType( 073 @Nullable JetType assignmentType, 074 @NotNull JetBinaryExpression expression, 075 @NotNull ExpressionTypingContext context 076 ) { 077 if (assignmentType != null && !KotlinBuiltIns.getInstance().isUnit(assignmentType) && context.expectedType != TypeUtils.NO_EXPECTED_TYPE && 078 TypeUtils.equalTypes(context.expectedType, assignmentType)) { 079 context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType)); 080 return null; 081 } 082 return DataFlowUtils.checkStatementType(expression, context); 083 } 084 085 @Override 086 public JetTypeInfo visitObjectDeclaration(JetObjectDeclaration declaration, ExpressionTypingContext context) { 087 TopDownAnalyzer.processClassOrObject(context.expressionTypingServices.getProject(), context.trace, scope, 088 scope.getContainingDeclaration(), declaration); 089 ClassDescriptor classDescriptor = context.trace.getBindingContext().get(BindingContext.CLASS, declaration); 090 if (classDescriptor != null) { 091 VariableDescriptor variableDescriptor = context.expressionTypingServices.getDescriptorResolver() 092 .resolveObjectDeclaration(scope.getContainingDeclaration(), declaration, classDescriptor, context.trace); 093 scope.addVariableDescriptor(variableDescriptor); 094 } 095 return DataFlowUtils.checkStatementType(declaration, context, context.dataFlowInfo); 096 } 097 098 @Override 099 public JetTypeInfo visitProperty(JetProperty property, ExpressionTypingContext context) { 100 JetTypeReference receiverTypeRef = property.getReceiverTypeRef(); 101 if (receiverTypeRef != null) { 102 context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef)); 103 } 104 105 JetPropertyAccessor getter = property.getGetter(); 106 if (getter != null) { 107 context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter)); 108 } 109 110 JetPropertyAccessor setter = property.getSetter(); 111 if (setter != null) { 112 context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter)); 113 } 114 115 JetExpression delegateExpression = property.getDelegateExpression(); 116 if (delegateExpression != null) { 117 context.expressionTypingServices.getType(scope, delegateExpression, TypeUtils.NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); 118 context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate())); 119 } 120 121 VariableDescriptor propertyDescriptor = context.expressionTypingServices.getDescriptorResolver(). 122 resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace); 123 JetExpression initializer = property.getInitializer(); 124 DataFlowInfo dataFlowInfo = context.dataFlowInfo; 125 if (initializer != null) { 126 JetType outType = propertyDescriptor.getType(); 127 JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType).replaceScope(scope)); 128 dataFlowInfo = typeInfo.getDataFlowInfo(); 129 } 130 131 { 132 VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName()); 133 ExpressionTypingUtils.checkVariableShadowing(context, propertyDescriptor, olderVariable); 134 } 135 136 scope.addVariableDescriptor(propertyDescriptor); 137 ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(property); 138 return DataFlowUtils.checkStatementType(property, context, dataFlowInfo); 139 } 140 141 @Override 142 public JetTypeInfo visitMultiDeclaration(JetMultiDeclaration multiDeclaration, ExpressionTypingContext context) { 143 JetExpression initializer = multiDeclaration.getInitializer(); 144 if (initializer == null) { 145 context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration)); 146 return JetTypeInfo.create(null, context.dataFlowInfo); 147 } 148 ExpressionReceiver expressionReceiver = 149 ExpressionTypingUtils.getExpressionReceiver(facade, initializer, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)); 150 DataFlowInfo dataFlowInfo = facade.getTypeInfo(initializer, context).getDataFlowInfo(); 151 if (expressionReceiver == null) { 152 return JetTypeInfo.create(null, dataFlowInfo); 153 } 154 ExpressionTypingUtils.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context); 155 return DataFlowUtils.checkStatementType(multiDeclaration, context, dataFlowInfo); 156 } 157 158 @Override 159 public JetTypeInfo visitNamedFunction(JetNamedFunction function, ExpressionTypingContext context) { 160 SimpleFunctionDescriptor functionDescriptor = context.expressionTypingServices.getDescriptorResolver(). 161 resolveFunctionDescriptorWithAnnotationArguments(scope.getContainingDeclaration(), scope, function, context.trace); 162 163 scope.addFunctionDescriptor(functionDescriptor); 164 JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace); 165 context.expressionTypingServices.checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace); 166 ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(function); 167 return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo); 168 } 169 170 @Override 171 public JetTypeInfo visitClass(JetClass klass, ExpressionTypingContext context) { 172 TopDownAnalyzer.processClassOrObject(context.expressionTypingServices.getProject(), context.trace, scope, 173 scope.getContainingDeclaration(), klass); 174 ClassDescriptor classDescriptor = context.trace.getBindingContext().get(BindingContext.CLASS, klass); 175 if (classDescriptor != null) { 176 scope.addClassifierDescriptor(classDescriptor); 177 } 178 return DataFlowUtils.checkStatementType(klass, context, context.dataFlowInfo); 179 } 180 181 @Override 182 public JetTypeInfo visitTypedef(JetTypedef typedef, ExpressionTypingContext context) { 183 return super.visitTypedef(typedef, context); // TODO 184 } 185 186 @Override 187 public JetTypeInfo visitDeclaration(JetDeclaration dcl, ExpressionTypingContext context) { 188 return DataFlowUtils.checkStatementType(dcl, context, context.dataFlowInfo); 189 } 190 191 @Override 192 public JetTypeInfo visitBinaryExpression(JetBinaryExpression expression, ExpressionTypingContext context) { 193 JetSimpleNameExpression operationSign = expression.getOperationReference(); 194 IElementType operationType = operationSign.getReferencedNameElementType(); 195 JetTypeInfo result; 196 if (operationType == JetTokens.EQ) { 197 result = visitAssignment(expression, context); 198 } 199 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { 200 result = visitAssignmentOperation(expression, context); 201 } 202 else { 203 return facade.getTypeInfo(expression, context); 204 } 205 return DataFlowUtils.checkType(result.getType(), expression, context, result.getDataFlowInfo()); 206 } 207 208 @NotNull 209 protected JetTypeInfo visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { 210 //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there) 211 TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create( 212 contextWithExpectedType.trace, "trace to resolve array set method for binary expression", expression); 213 ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceBindingTrace(temporaryBindingTrace); 214 215 JetSimpleNameExpression operationSign = expression.getOperationReference(); 216 IElementType operationType = operationSign.getReferencedNameElementType(); 217 JetExpression leftOperand = expression.getLeft(); 218 JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade); 219 JetType leftType = leftInfo.getType(); 220 DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); 221 222 JetExpression right = expression.getRight(); 223 JetExpression left = leftOperand == null ? null : JetPsiUtil.deparenthesizeWithNoTypeResolution(leftOperand); 224 if (right == null || left == null) { 225 temporaryBindingTrace.commit(); 226 return JetTypeInfo.create(null, dataFlowInfo); 227 } 228 229 if (leftType == null) { 230 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); 231 context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign)); 232 temporaryBindingTrace.commit(); 233 return JetTypeInfo.create(null, dataFlowInfo); 234 } 235 ExpressionReceiver receiver = new ExpressionReceiver(left, leftType); 236 237 // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign) 238 // Check for '+=' 239 Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType); 240 TemporaryBindingTrace assignmentOperationTrace = TemporaryBindingTrace.create(context.trace, "trace to check assignment operation like '+=' for", expression); 241 OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors = BasicExpressionTypingVisitor.getResolutionResultsForBinaryCall( 242 scope, name, context.replaceBindingTrace(assignmentOperationTrace), expression, receiver); 243 JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultType(assignmentOperationDescriptors); 244 245 // Check for '+' 246 Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType)); 247 TemporaryBindingTrace binaryOperationTrace = TemporaryBindingTrace.create(context.trace, "trace to check binary operation like '+' for", expression); 248 OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors = BasicExpressionTypingVisitor.getResolutionResultsForBinaryCall( 249 scope, counterpartName, context.replaceBindingTrace(binaryOperationTrace), expression, receiver); 250 JetType binaryOperationType = OverloadResolutionResultsUtil.getResultType(binaryOperationDescriptors); 251 252 JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType; 253 if (assignmentOperationType != null && binaryOperationType != null) { 254 // Both 'plus()' and 'plusAssign()' available => ambiguity 255 OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors); 256 context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls())); 257 Collection<DeclarationDescriptor> descriptors = Sets.newHashSet(); 258 for (ResolvedCall<? extends FunctionDescriptor> call : ambiguityResolutionResults.getResultingCalls()) { 259 descriptors.add(call.getResultingDescriptor()); 260 } 261 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); 262 context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors); 263 } 264 else if (assignmentOperationType != null) { 265 // There's 'plusAssign()', so we do a.plusAssign(b) 266 assignmentOperationTrace.commit(); 267 if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) { 268 context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign)); 269 } 270 } 271 else { 272 // There's only 'plus()', so we try 'a = a + b' 273 binaryOperationTrace.commit(); 274 context.trace.record(VARIABLE_REASSIGNMENT, expression); 275 if (left instanceof JetArrayAccessExpression) { 276 ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create( 277 contextWithExpectedType.trace, "trace to resolve array set method for assignment", expression)); 278 basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace); 279 } 280 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); 281 BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand); 282 } 283 temporaryBindingTrace.commit(); 284 return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo); 285 } 286 287 @NotNull 288 protected JetTypeInfo visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { 289 ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope); 290 JetExpression leftOperand = expression.getLeft(); 291 JetExpression left = leftOperand == null ? null : context.expressionTypingServices.deparenthesize(leftOperand, context); 292 JetExpression right = expression.getRight(); 293 if (left instanceof JetArrayAccessExpression) { 294 JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; 295 if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo); 296 JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace); 297 BasicExpressionTypingVisitor.checkLValue(context.trace, arrayAccessExpression); 298 return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType), 299 typeInfo.getDataFlowInfo()); 300 } 301 JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade); 302 JetType leftType = leftInfo.getType(); 303 DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); 304 if (right != null) { 305 JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType)); 306 dataFlowInfo = rightInfo.getDataFlowInfo(); 307 } 308 if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated 309 BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand); 310 } 311 return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo); 312 } 313 314 315 @Override 316 public JetTypeInfo visitExpression(JetExpression expression, ExpressionTypingContext context) { 317 return facade.getTypeInfo(expression, context); 318 } 319 320 @Override 321 public JetTypeInfo visitJetElement(JetElement element, ExpressionTypingContext context) { 322 context.trace.report(UNSUPPORTED.on(element, "in a block")); 323 return JetTypeInfo.create(null, context.dataFlowInfo); 324 } 325 326 @Override 327 public JetTypeInfo visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext context) { 328 return controlStructures.visitWhileExpression(expression, context, true); 329 } 330 331 @Override 332 public JetTypeInfo visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext context) { 333 return controlStructures.visitDoWhileExpression(expression, context, true); 334 } 335 336 @Override 337 public JetTypeInfo visitForExpression(JetForExpression expression, ExpressionTypingContext context) { 338 return controlStructures.visitForExpression(expression, context, true); 339 } 340 341 @Override 342 public JetTypeInfo visitIfExpression(JetIfExpression expression, ExpressionTypingContext context) { 343 return controlStructures.visitIfExpression(expression, context, true); 344 } 345 346 @Override 347 public JetTypeInfo visitWhenExpression(JetWhenExpression expression, ExpressionTypingContext context) { 348 return patterns.visitWhenExpression(expression, context, true); 349 } 350 351 @Override 352 public JetTypeInfo visitBlockExpression(JetBlockExpression expression, ExpressionTypingContext context) { 353 return BasicExpressionTypingVisitor.visitBlockExpression(expression, context, true); 354 } 355 356 @Override 357 public JetTypeInfo visitParenthesizedExpression(JetParenthesizedExpression expression, ExpressionTypingContext context) { 358 return basic.visitParenthesizedExpression(expression, context, true); 359 } 360 361 @Override 362 public JetTypeInfo visitUnaryExpression(JetUnaryExpression expression, ExpressionTypingContext context) { 363 return basic.visitUnaryExpression(expression, context, true); 364 } 365}