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