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