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