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.DeclarationDescriptor;
024 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
025 import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
026 import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
027 import org.jetbrains.jet.lang.diagnostics.Errors;
028 import org.jetbrains.jet.lang.psi.*;
029 import org.jetbrains.jet.lang.resolve.*;
030 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
031 import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache;
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 import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
051 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
052 import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
053
054 @SuppressWarnings("SuspiciousMethodCalls")
055 public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisitor {
056 private final WritableScope scope;
057 private final BasicExpressionTypingVisitor basic;
058 private final ControlStructureTypingVisitor controlStructures;
059 private final PatternMatchingTypingVisitor patterns;
060
061 public ExpressionTypingVisitorForStatements(
062 @NotNull ExpressionTypingInternals facade,
063 @NotNull WritableScope scope,
064 BasicExpressionTypingVisitor basic,
065 @NotNull ControlStructureTypingVisitor controlStructures,
066 @NotNull PatternMatchingTypingVisitor patterns) {
067 super(facade);
068 this.scope = scope;
069 this.basic = basic;
070 this.controlStructures = controlStructures;
071 this.patterns = patterns;
072 }
073
074 @Nullable
075 private static JetType checkAssignmentType(
076 @Nullable JetType assignmentType,
077 @NotNull JetBinaryExpression expression,
078 @NotNull ExpressionTypingContext context
079 ) {
080 if (assignmentType != null && !KotlinBuiltIns.getInstance().isUnit(assignmentType) && !noExpectedType(context.expectedType) &&
081 TypeUtils.equalTypes(context.expectedType, assignmentType)) {
082 context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType));
083 return null;
084 }
085 return DataFlowUtils.checkStatementType(expression, context);
086 }
087
088 @Override
089 public JetTypeInfo visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, ExpressionTypingContext context) {
090 TopDownAnalyzer.processClassOrObject(
091 components.globalContext,
092 scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), declaration,
093 components.additionalCheckerProvider);
094 return DataFlowUtils.checkStatementType(declaration, context, context.dataFlowInfo);
095 }
096
097 @Override
098 public JetTypeInfo visitProperty(@NotNull JetProperty property, ExpressionTypingContext typingContext) {
099 ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT).replaceScope(scope);
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 components.expressionTypingServices.getTypeInfo(delegateExpression, context);
118 context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate()));
119 }
120
121 for (JetTypeParameter typeParameter : property.getTypeParameters()) {
122 AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(typeParameter, context.trace);
123 }
124
125 VariableDescriptor propertyDescriptor = components.expressionTypingServices.getDescriptorResolver().
126 resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace);
127 JetExpression initializer = property.getInitializer();
128 DataFlowInfo dataFlowInfo = context.dataFlowInfo;
129 if (initializer != null) {
130 JetType outType = propertyDescriptor.getType();
131 JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
132 dataFlowInfo = typeInfo.getDataFlowInfo();
133 }
134
135 {
136 VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName());
137 ExpressionTypingUtils.checkVariableShadowing(context, propertyDescriptor, olderVariable);
138 }
139
140 scope.addVariableDescriptor(propertyDescriptor);
141 ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor);
142 return DataFlowUtils.checkStatementType(property, context, dataFlowInfo);
143 }
144
145 @Override
146 public JetTypeInfo visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, ExpressionTypingContext context) {
147 components.expressionTypingServices.getAnnotationResolver().resolveAnnotationsWithArguments(
148 scope, multiDeclaration.getModifierList(), context.trace);
149
150 JetExpression initializer = multiDeclaration.getInitializer();
151 if (initializer == null) {
152 context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration));
153 return JetTypeInfo.create(null, context.dataFlowInfo);
154 }
155 ExpressionReceiver expressionReceiver = ExpressionTypingUtils.getExpressionReceiver(
156 facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
157 DataFlowInfo dataFlowInfo = facade.getTypeInfo(initializer, context).getDataFlowInfo();
158 if (expressionReceiver == null) {
159 return JetTypeInfo.create(null, dataFlowInfo);
160 }
161 components.expressionTypingUtils.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
162 return DataFlowUtils.checkStatementType(multiDeclaration, context, dataFlowInfo);
163 }
164
165 @Override
166 public JetTypeInfo visitNamedFunction(@NotNull JetNamedFunction function, ExpressionTypingContext context) {
167 SimpleFunctionDescriptor functionDescriptor = components.expressionTypingServices.getDescriptorResolver().
168 resolveFunctionDescriptorWithAnnotationArguments(
169 scope.getContainingDeclaration(), scope, function, context.trace, context.dataFlowInfo);
170
171 scope.addFunctionDescriptor(functionDescriptor);
172 JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
173 components.expressionTypingServices.checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace);
174
175 components.expressionTypingServices.resolveValueParameters(function.getValueParameters(), functionDescriptor.getValueParameters(),
176 scope, context.dataFlowInfo, context.trace, /* needCompleteAnalysis = */ true);
177
178 ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(function, functionDescriptor);
179 if (!function.hasBody()) {
180 context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
181 }
182 return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo);
183 }
184
185 @Override
186 public JetTypeInfo visitClass(@NotNull JetClass klass, ExpressionTypingContext context) {
187 TopDownAnalyzer.processClassOrObject(
188 components.globalContext,
189 scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), klass,
190 components.additionalCheckerProvider);
191 return DataFlowUtils.checkStatementType(klass, context, context.dataFlowInfo);
192 }
193
194 @Override
195 public JetTypeInfo visitTypedef(@NotNull JetTypedef typedef, ExpressionTypingContext context) {
196 context.trace.report(UNSUPPORTED.on(typedef, "Typedefs are not supported"));
197 return super.visitTypedef(typedef, context);
198 }
199
200 @Override
201 public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) {
202 return DataFlowUtils.checkStatementType(dcl, context, context.dataFlowInfo);
203 }
204
205 @Override
206 public JetTypeInfo visitBinaryExpression(@NotNull JetBinaryExpression expression, ExpressionTypingContext context) {
207 JetSimpleNameExpression operationSign = expression.getOperationReference();
208 IElementType operationType = operationSign.getReferencedNameElementType();
209 JetTypeInfo result;
210 if (operationType == JetTokens.EQ) {
211 result = visitAssignment(expression, context);
212 }
213 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
214 result = visitAssignmentOperation(expression, context);
215 }
216 else {
217 return facade.getTypeInfo(expression, context);
218 }
219 return DataFlowUtils.checkType(result.getType(), expression, context, result.getDataFlowInfo());
220 }
221
222 @NotNull
223 protected JetTypeInfo visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
224 //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
225 TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(
226 contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
227 ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE)
228 .replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
229
230 JetSimpleNameExpression operationSign = expression.getOperationReference();
231 IElementType operationType = operationSign.getReferencedNameElementType();
232 JetExpression leftOperand = expression.getLeft();
233 JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
234 JetType leftType = leftInfo.getType();
235 DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
236
237 JetExpression right = expression.getRight();
238 JetExpression left = leftOperand == null ? null : JetPsiUtil.deparenthesize(leftOperand);
239 if (right == null || left == null) {
240 temporary.commit();
241 return JetTypeInfo.create(null, dataFlowInfo);
242 }
243
244 if (leftType == null) {
245 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
246 context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
247 temporary.commit();
248 return JetTypeInfo.create(null, dataFlowInfo);
249 }
250 ExpressionReceiver receiver = new ExpressionReceiver(left, leftType);
251
252 // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
253 // Check for '+='
254 Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
255 TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(
256 context, "trace to check assignment operation like '+=' for", expression);
257 OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors =
258 components.callResolver.resolveBinaryCall(
259 context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope),
260 receiver, expression, name
261 );
262 JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors,
263 context.contextDependency);
264
265 // Check for '+'
266 Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
267 TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
268 context, "trace to check binary operation like '+' for", expression);
269 OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors = components.callResolver.resolveBinaryCall(
270 context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope),
271 receiver, expression, counterpartName
272 );
273 JetType binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
274
275 JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
276 if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess()) {
277 // Both 'plus()' and 'plusAssign()' available => ambiguity
278 OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
279 context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
280 Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
281 for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
282 descriptors.add(resolvedCall.getResultingDescriptor());
283 }
284 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
285 context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
286 }
287 else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
288 // There's 'plusAssign()', so we do a.plusAssign(b)
289 temporaryForAssignmentOperation.commit();
290 if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) {
291 context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
292 }
293 }
294 else {
295 // There's only 'plus()', so we try 'a = a + b'
296 temporaryForBinaryOperation.commit();
297 context.trace.record(VARIABLE_REASSIGNMENT, expression);
298 if (left instanceof JetArrayAccessExpression) {
299 ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(
300 context.trace, "trace to resolve array set method for assignment", expression));
301 basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace);
302 }
303 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
304 DataFlowUtils.checkType(binaryOperationType, expression, leftType, dataFlowInfo, context.trace);
305 BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
306 }
307 temporary.commit();
308 return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo);
309 }
310
311 @NotNull
312 protected JetTypeInfo visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
313 ExpressionTypingContext context =
314 contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(scope).replaceContextDependency(INDEPENDENT);
315 JetExpression leftOperand = expression.getLeft();
316 JetExpression left = components.expressionTypingServices.deparenthesizeWithTypeResolution(leftOperand, context);
317 JetExpression right = expression.getRight();
318 if (left instanceof JetArrayAccessExpression) {
319 JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
320 if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo);
321 JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
322 BasicExpressionTypingVisitor.checkLValue(context.trace, arrayAccessExpression);
323 return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType),
324 typeInfo.getDataFlowInfo());
325 }
326 JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
327 JetType leftType = leftInfo.getType();
328 DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
329 if (right != null) {
330 JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
331 dataFlowInfo = rightInfo.getDataFlowInfo();
332 }
333 if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
334 BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
335 }
336 return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo);
337 }
338
339
340 @Override
341 public JetTypeInfo visitExpression(@NotNull JetExpression expression, ExpressionTypingContext context) {
342 return facade.getTypeInfo(expression, context);
343 }
344
345 @Override
346 public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext context) {
347 context.trace.report(UNSUPPORTED.on(element, "in a block"));
348 return JetTypeInfo.create(null, context.dataFlowInfo);
349 }
350
351 @Override
352 public JetTypeInfo visitWhileExpression(@NotNull JetWhileExpression expression, ExpressionTypingContext context) {
353 return controlStructures.visitWhileExpression(expression, context, true);
354 }
355
356 @Override
357 public JetTypeInfo visitDoWhileExpression(@NotNull JetDoWhileExpression expression, ExpressionTypingContext context) {
358 return controlStructures.visitDoWhileExpression(expression, context, true);
359 }
360
361 @Override
362 public JetTypeInfo visitForExpression(@NotNull JetForExpression expression, ExpressionTypingContext context) {
363 return controlStructures.visitForExpression(expression, context, true);
364 }
365
366 @Override
367 public JetTypeInfo visitAnnotatedExpression(
368 @NotNull JetAnnotatedExpression expression, ExpressionTypingContext data
369 ) {
370 return basic.visitAnnotatedExpression(expression, data, true);
371 }
372
373 @Override
374 public JetTypeInfo visitIfExpression(@NotNull JetIfExpression expression, ExpressionTypingContext context) {
375 return controlStructures.visitIfExpression(expression, context, true);
376 }
377
378 @Override
379 public JetTypeInfo visitWhenExpression(@NotNull JetWhenExpression expression, ExpressionTypingContext context) {
380 return patterns.visitWhenExpression(expression, context, true);
381 }
382
383 @Override
384 public JetTypeInfo visitBlockExpression(@NotNull JetBlockExpression expression, ExpressionTypingContext context) {
385 return components.expressionTypingServices.getBlockReturnedType(expression, context, true);
386 }
387
388 @Override
389 public JetTypeInfo visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, ExpressionTypingContext context) {
390 return basic.visitParenthesizedExpression(expression, context, true);
391 }
392
393 @Override
394 public JetTypeInfo visitLabeledExpression(@NotNull JetLabeledExpression expression, ExpressionTypingContext context) {
395 return basic.visitLabeledExpression(expression, context, true);
396 }
397 }