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
017 package org.jetbrains.jet.lang.types.expressions;
018
019 import com.google.common.collect.Sets;
020 import com.intellij.psi.tree.IElementType;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorUtil;
025 import org.jetbrains.jet.lang.diagnostics.Errors;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.BindingContext;
028 import org.jetbrains.jet.lang.resolve.ModifiersChecker;
029 import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
030 import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
031 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
032 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
033 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
034 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
035 import org.jetbrains.jet.lang.resolve.name.Name;
036 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
037 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
038 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
039 import org.jetbrains.jet.lang.types.JetType;
040 import org.jetbrains.jet.lang.types.JetTypeInfo;
041 import org.jetbrains.jet.lang.types.TypeUtils;
042 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
043 import org.jetbrains.jet.lexer.JetTokens;
044
045 import java.util.Collection;
046
047 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
048 import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET;
049 import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT;
050
051 @SuppressWarnings("SuspiciousMethodCalls")
052 public 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 }