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