001 /*
002 * Copyright 2010-2015 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.kotlin.types.expressions;
018
019 import com.google.common.collect.Sets;
020 import com.intellij.psi.tree.IElementType;
021 import kotlin.Pair;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025 import org.jetbrains.kotlin.descriptors.*;
026 import org.jetbrains.kotlin.diagnostics.Errors;
027 import org.jetbrains.kotlin.lexer.KtTokens;
028 import org.jetbrains.kotlin.name.Name;
029 import org.jetbrains.kotlin.psi.*;
030 import org.jetbrains.kotlin.resolve.BindingContext;
031 import org.jetbrains.kotlin.resolve.BindingContextUtils;
032 import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
033 import org.jetbrains.kotlin.resolve.calls.context.CallPosition;
034 import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
035 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
036 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
037 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
038 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
039 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
040 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
041 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
042 import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
043 import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
044 import org.jetbrains.kotlin.types.KotlinType;
045 import org.jetbrains.kotlin.types.TypeUtils;
046 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
047 import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
048
049 import java.util.Collection;
050
051 import static org.jetbrains.kotlin.diagnostics.Errors.*;
052 import static org.jetbrains.kotlin.psi.KtPsiUtil.deparenthesize;
053 import static org.jetbrains.kotlin.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET;
054 import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE_REASSIGNMENT;
055 import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
056 import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
057 import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType;
058
059 @SuppressWarnings("SuspiciousMethodCalls")
060 public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisitor {
061 private final LexicalWritableScope scope;
062 private final BasicExpressionTypingVisitor basic;
063 private final ControlStructureTypingVisitor controlStructures;
064 private final PatternMatchingTypingVisitor patterns;
065 private final FunctionsTypingVisitor functions;
066
067 public ExpressionTypingVisitorForStatements(
068 @NotNull ExpressionTypingInternals facade,
069 @NotNull LexicalWritableScope scope,
070 @NotNull BasicExpressionTypingVisitor basic,
071 @NotNull ControlStructureTypingVisitor controlStructures,
072 @NotNull PatternMatchingTypingVisitor patterns,
073 @NotNull FunctionsTypingVisitor functions
074 ) {
075 super(facade);
076 this.scope = scope;
077 this.basic = basic;
078 this.controlStructures = controlStructures;
079 this.patterns = patterns;
080 this.functions = functions;
081 }
082
083 @Nullable
084 private KotlinType checkAssignmentType(
085 @Nullable KotlinType assignmentType,
086 @NotNull KtBinaryExpression expression,
087 @NotNull ExpressionTypingContext context
088 ) {
089 if (assignmentType != null && !KotlinBuiltIns.isUnit(assignmentType) && !noExpectedType(context.expectedType) &&
090 !context.expectedType.isError() && TypeUtils.equalTypes(context.expectedType, assignmentType)) {
091 context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType));
092 return null;
093 }
094 return components.dataFlowAnalyzer.checkStatementType(expression, context);
095 }
096
097 @Override
098 public KotlinTypeInfo visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, ExpressionTypingContext context) {
099 components.localClassifierAnalyzer.processClassOrObject(
100 scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT),
101 scope.getOwnerDescriptor(),
102 declaration);
103 return TypeInfoFactoryKt.createTypeInfo(components.dataFlowAnalyzer.checkStatementType(declaration, context), context);
104 }
105
106 @Override
107 public KotlinTypeInfo visitProperty(@NotNull KtProperty property, ExpressionTypingContext typingContext) {
108 Pair<KotlinTypeInfo, VariableDescriptor> typeInfoAndVariableDescriptor = components.localVariableResolver.process(property, typingContext, scope, facade);
109 scope.addVariableDescriptor(typeInfoAndVariableDescriptor.getSecond());
110 return typeInfoAndVariableDescriptor.getFirst();
111 }
112
113 @Override
114 public KotlinTypeInfo visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, ExpressionTypingContext context) {
115 components.annotationResolver.resolveAnnotationsWithArguments(scope, multiDeclaration.getModifierList(), context.trace);
116
117 KtExpression initializer = multiDeclaration.getInitializer();
118 if (initializer == null) {
119 context.trace.report(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION.on(multiDeclaration));
120 }
121
122 ExpressionReceiver expressionReceiver = initializer != null ? ExpressionTypingUtils.getExpressionReceiver(
123 facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)) : null;
124
125 components.destructuringDeclarationResolver
126 .defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
127 components.modifiersChecker.withTrace(context.trace).checkModifiersForDestructuringDeclaration(multiDeclaration);
128 components.identifierChecker.checkDeclaration(multiDeclaration, context.trace);
129
130 if (expressionReceiver == null) {
131 return TypeInfoFactoryKt.noTypeInfo(context);
132 }
133 else {
134 return facade.getTypeInfo(initializer, context)
135 .replaceType(components.dataFlowAnalyzer.checkStatementType(multiDeclaration, context));
136 }
137 }
138
139 @Override
140 public KotlinTypeInfo visitNamedFunction(@NotNull KtNamedFunction function, ExpressionTypingContext context) {
141 return functions.visitNamedFunction(function, context, /* isDeclaration = */ function.getName() != null, scope);
142 }
143
144 @Override
145 public KotlinTypeInfo visitClass(@NotNull KtClass klass, ExpressionTypingContext context) {
146 components.localClassifierAnalyzer.processClassOrObject(
147 scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT),
148 scope.getOwnerDescriptor(),
149 klass);
150 return TypeInfoFactoryKt.createTypeInfo(components.dataFlowAnalyzer.checkStatementType(klass, context), context);
151 }
152
153 @Override
154 public KotlinTypeInfo visitDeclaration(@NotNull KtDeclaration dcl, ExpressionTypingContext context) {
155 return TypeInfoFactoryKt.createTypeInfo(components.dataFlowAnalyzer.checkStatementType(dcl, context), context);
156 }
157
158 @Override
159 public KotlinTypeInfo visitBinaryExpression(@NotNull KtBinaryExpression expression, ExpressionTypingContext context) {
160 KtSimpleNameExpression operationSign = expression.getOperationReference();
161 IElementType operationType = operationSign.getReferencedNameElementType();
162 KotlinTypeInfo result;
163 if (operationType == KtTokens.EQ) {
164 result = visitAssignment(expression, context);
165 }
166 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
167 result = visitAssignmentOperation(expression, context);
168 }
169 else {
170 return facade.getTypeInfo(expression, context);
171 }
172 return components.dataFlowAnalyzer.checkType(result, expression, context);
173 }
174
175 @NotNull
176 protected KotlinTypeInfo visitAssignmentOperation(KtBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
177 //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
178 TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(
179 contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
180 ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE)
181 .replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
182
183 KtSimpleNameExpression operationSign = expression.getOperationReference();
184 IElementType operationType = operationSign.getReferencedNameElementType();
185 KtExpression leftOperand = expression.getLeft();
186 KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
187 KotlinType leftType = leftInfo.getType();
188
189 KtExpression right = expression.getRight();
190 KtExpression left = leftOperand == null ? null : deparenthesize(leftOperand);
191 if (right == null || left == null) {
192 temporary.commit();
193 return leftInfo.clearType();
194 }
195
196 if (leftType == null) {
197 KotlinTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
198 context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
199 temporary.commit();
200 return rightInfo.clearType();
201 }
202 ExpressionReceiver receiver = ExpressionReceiver.Companion.create(left, leftType, context.trace.getBindingContext());
203
204 // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
205 // Check for '+='
206 Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
207 TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(
208 context, "trace to check assignment operation like '+=' for", expression);
209 OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors =
210 components.callResolver.resolveBinaryCall(
211 context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope),
212 receiver, expression, name
213 );
214 KotlinType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors,
215 context.contextDependency);
216
217 OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors;
218 KotlinType binaryOperationType;
219 TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
220 context, "trace to check binary operation like '+' for", expression);
221 TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability");
222 boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right, expression);
223 if (assignmentOperationType == null || lhsAssignable) {
224 // Check for '+'
225 Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
226 binaryOperationDescriptors = components.callResolver.resolveBinaryCall(
227 context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope),
228 receiver, expression, counterpartName
229 );
230
231 binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
232 }
233 else {
234 binaryOperationDescriptors = OverloadResolutionResultsImpl.nameNotFound();
235 binaryOperationType = null;
236 }
237
238 KotlinType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
239 KotlinTypeInfo rightInfo = leftInfo;
240 if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess()) {
241 // Both 'plus()' and 'plusAssign()' available => ambiguity
242 OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
243 context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
244 Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
245 for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
246 descriptors.add(resolvedCall.getResultingDescriptor());
247 }
248 rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
249 context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
250 }
251 else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
252 // There's 'plusAssign()', so we do a.plusAssign(b)
253 temporaryForAssignmentOperation.commit();
254 if (!KotlinTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) {
255 context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
256 }
257 }
258 else {
259 // There's only 'plus()', so we try 'a = a + b'
260 temporaryForBinaryOperation.commit();
261 context.trace.record(VARIABLE_REASSIGNMENT, expression);
262 if (left instanceof KtArrayAccessExpression) {
263 ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(
264 context.trace, "trace to resolve array set method for assignment", expression));
265 basic.resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) left, right, contextForResolve, context.trace);
266 }
267 rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
268
269 KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftType);
270
271 components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType)
272 .replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left)));
273 basic.checkLValue(context.trace, context, leftOperand, right, expression);
274 }
275 temporary.commit();
276 return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
277 }
278
279 @Nullable
280 private static KotlinType refineTypeFromPropertySetterIfPossible(
281 @NotNull BindingContext bindingContext,
282 @Nullable KtElement leftOperand,
283 @Nullable KotlinType leftOperandType
284 ) {
285 VariableDescriptor descriptor = BindingContextUtils.extractVariableFromResolvedCall(bindingContext, leftOperand);
286
287 if (descriptor instanceof PropertyDescriptor) {
288 PropertySetterDescriptor setter = ((PropertyDescriptor) descriptor).getSetter();
289 if (setter != null) return setter.getValueParameters().get(0).getType();
290 }
291
292 return leftOperandType;
293 }
294
295 @NotNull
296 protected KotlinTypeInfo visitAssignment(KtBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
297 ExpressionTypingContext context =
298 contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(scope).replaceContextDependency(INDEPENDENT);
299 KtExpression leftOperand = expression.getLeft();
300 if (leftOperand instanceof KtAnnotatedExpression) {
301 // We will lose all annotations during deparenthesizing, so we have to resolve them right now
302 components.annotationResolver.resolveAnnotationsWithArguments(
303 scope, ((KtAnnotatedExpression) leftOperand).getAnnotationEntries(), context.trace
304 );
305 }
306 KtExpression left = deparenthesize(leftOperand);
307 KtExpression right = expression.getRight();
308 if (left instanceof KtArrayAccessExpression) {
309 KtArrayAccessExpression arrayAccessExpression = (KtArrayAccessExpression) left;
310 if (right == null) return TypeInfoFactoryKt.noTypeInfo(context);
311 KotlinTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
312 basic.checkLValue(context.trace, context, arrayAccessExpression, right, expression);
313 return typeInfo.replaceType(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType));
314 }
315 KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
316 KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftInfo.getType());
317 DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
318 KotlinTypeInfo resultInfo;
319 if (right != null) {
320 resultInfo = facade.getTypeInfo(
321 right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(expectedType).replaceCallPosition(
322 new CallPosition.PropertyAssignment(leftOperand)));
323
324 dataFlowInfo = resultInfo.getDataFlowInfo();
325 KotlinType rightType = resultInfo.getType();
326 if (left != null && expectedType != null && rightType != null) {
327 DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, expectedType, context);
328 DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context);
329 // We cannot say here anything new about rightValue except it has the same value as leftValue
330 resultInfo = resultInfo.replaceDataFlowInfo(dataFlowInfo.assign(leftValue, rightValue));
331 }
332 }
333 else {
334 resultInfo = leftInfo;
335 }
336 if (expectedType != null && leftOperand != null) { //if expectedType == null, some other error has been generated
337 basic.checkLValue(context.trace, context, leftOperand, right, expression);
338 }
339 return resultInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(expression, contextWithExpectedType));
340 }
341
342
343 @Override
344 public KotlinTypeInfo visitExpression(@NotNull KtExpression expression, ExpressionTypingContext context) {
345 return facade.getTypeInfo(expression, context);
346 }
347
348 @Override
349 public KotlinTypeInfo visitKtElement(@NotNull KtElement element, ExpressionTypingContext context) {
350 context.trace.report(UNSUPPORTED.on(element, "in a block"));
351 return TypeInfoFactoryKt.noTypeInfo(context);
352 }
353
354 @Override
355 public KotlinTypeInfo visitWhileExpression(@NotNull KtWhileExpression expression, ExpressionTypingContext context) {
356 return controlStructures.visitWhileExpression(expression, context, true);
357 }
358
359 @Override
360 public KotlinTypeInfo visitDoWhileExpression(@NotNull KtDoWhileExpression expression, ExpressionTypingContext context) {
361 return controlStructures.visitDoWhileExpression(expression, context, true);
362 }
363
364 @Override
365 public KotlinTypeInfo visitForExpression(@NotNull KtForExpression expression, ExpressionTypingContext context) {
366 return controlStructures.visitForExpression(expression, context, true);
367 }
368
369 @Override
370 public KotlinTypeInfo visitAnnotatedExpression(
371 @NotNull KtAnnotatedExpression expression, ExpressionTypingContext data
372 ) {
373 return basic.visitAnnotatedExpression(expression, data, true);
374 }
375
376 @Override
377 public KotlinTypeInfo visitIfExpression(@NotNull KtIfExpression expression, ExpressionTypingContext context) {
378 return controlStructures.visitIfExpression(expression, context, true);
379 }
380
381 @Override
382 public KotlinTypeInfo visitWhenExpression(@NotNull KtWhenExpression expression, ExpressionTypingContext context) {
383 return patterns.visitWhenExpression(expression, context, true);
384 }
385
386 @Override
387 public KotlinTypeInfo visitBlockExpression(@NotNull KtBlockExpression expression, ExpressionTypingContext context) {
388 return components.expressionTypingServices.getBlockReturnedType(expression, context, true);
389 }
390
391 @Override
392 public KotlinTypeInfo visitLabeledExpression(@NotNull KtLabeledExpression expression, ExpressionTypingContext context) {
393 return basic.visitLabeledExpression(expression, context, true);
394 }
395 }