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 org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
024 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
025 import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
026 import org.jetbrains.kotlin.descriptors.VariableDescriptor;
027 import org.jetbrains.kotlin.diagnostics.Errors;
028 import org.jetbrains.kotlin.lexer.KtTokens;
029 import org.jetbrains.kotlin.name.Name;
030 import org.jetbrains.kotlin.psi.*;
031 import org.jetbrains.kotlin.resolve.DeclarationsCheckerKt;
032 import org.jetbrains.kotlin.resolve.DescriptorUtils;
033 import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
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 ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT).replaceScope(scope);
109 KtTypeReference receiverTypeRef = property.getReceiverTypeReference();
110 if (receiverTypeRef != null) {
111 context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef));
112 }
113
114 KtPropertyAccessor getter = property.getGetter();
115 if (getter != null) {
116 context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter));
117 }
118
119 KtPropertyAccessor setter = property.getSetter();
120 if (setter != null) {
121 context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter));
122 }
123
124 KtExpression delegateExpression = property.getDelegateExpression();
125 if (delegateExpression != null) {
126 components.expressionTypingServices.getTypeInfo(delegateExpression, context);
127 context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate()));
128 }
129
130 VariableDescriptor propertyDescriptor = components.descriptorResolver.
131 resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace);
132 KtExpression initializer = property.getInitializer();
133 KotlinTypeInfo typeInfo;
134 if (initializer != null) {
135 KotlinType outType = propertyDescriptor.getType();
136 typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
137 DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
138 KotlinType type = typeInfo.getType();
139 // At this moment we do not take initializer value into account if type is given for a property
140 // We can comment first part of this condition to take them into account, like here: var s: String? = "xyz"
141 // In this case s will be not-nullable until it is changed
142 if (property.getTypeReference() == null && type != null) {
143 DataFlowValue variableDataFlowValue = DataFlowValueFactory.createDataFlowValueForProperty(
144 property, propertyDescriptor, context.trace.getBindingContext(),
145 DescriptorUtils.getContainingModuleOrNull(scope.getOwnerDescriptor()));
146 DataFlowValue initializerDataFlowValue = DataFlowValueFactory.createDataFlowValue(initializer, type, context);
147 // We cannot say here anything new about initializerDataFlowValue
148 // except it has the same value as variableDataFlowValue
149 typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.assign(variableDataFlowValue, initializerDataFlowValue));
150 }
151 }
152 else {
153 typeInfo = TypeInfoFactoryKt.noTypeInfo(context);
154 }
155
156 ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, propertyDescriptor);
157
158 scope.addVariableDescriptor(propertyDescriptor);
159 DeclarationsCheckerKt.checkTypeReferences(property, context.trace);
160 components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor);
161 components.identifierChecker.checkDeclaration(property, context.trace);
162 return typeInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(property, context));
163 }
164
165 @Override
166 public KotlinTypeInfo visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, ExpressionTypingContext context) {
167 components.annotationResolver.resolveAnnotationsWithArguments(scope, multiDeclaration.getModifierList(), context.trace);
168
169 KtExpression initializer = multiDeclaration.getInitializer();
170 if (initializer == null) {
171 context.trace.report(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION.on(multiDeclaration));
172 return TypeInfoFactoryKt.noTypeInfo(context);
173 }
174 ExpressionReceiver expressionReceiver = ExpressionTypingUtils.getExpressionReceiver(
175 facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
176 KotlinTypeInfo typeInfo = facade.getTypeInfo(initializer, context);
177 if (expressionReceiver == null) {
178 return TypeInfoFactoryKt.noTypeInfo(context);
179 }
180 components.destructuringDeclarationResolver
181 .defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
182 components.modifiersChecker.withTrace(context.trace).checkModifiersForDestructuringDeclaration(multiDeclaration);
183 components.identifierChecker.checkDeclaration(multiDeclaration, context.trace);
184 return typeInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(multiDeclaration, context));
185 }
186
187 @Override
188 public KotlinTypeInfo visitNamedFunction(@NotNull KtNamedFunction function, ExpressionTypingContext context) {
189 return functions.visitNamedFunction(function, context, true, scope);
190 }
191
192 @Override
193 public KotlinTypeInfo visitClass(@NotNull KtClass klass, ExpressionTypingContext context) {
194 components.localClassifierAnalyzer.processClassOrObject(
195 scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT),
196 scope.getOwnerDescriptor(),
197 klass);
198 return TypeInfoFactoryKt.createTypeInfo(components.dataFlowAnalyzer.checkStatementType(klass, context), context);
199 }
200
201 @Override
202 public KotlinTypeInfo visitTypedef(@NotNull KtTypedef typedef, ExpressionTypingContext context) {
203 context.trace.report(UNSUPPORTED.on(typedef, "Typedefs are not supported"));
204 return super.visitTypedef(typedef, context);
205 }
206
207 @Override
208 public KotlinTypeInfo visitDeclaration(@NotNull KtDeclaration dcl, ExpressionTypingContext context) {
209 return TypeInfoFactoryKt.createTypeInfo(components.dataFlowAnalyzer.checkStatementType(dcl, context), context);
210 }
211
212 @Override
213 public KotlinTypeInfo visitBinaryExpression(@NotNull KtBinaryExpression expression, ExpressionTypingContext context) {
214 KtSimpleNameExpression operationSign = expression.getOperationReference();
215 IElementType operationType = operationSign.getReferencedNameElementType();
216 KotlinTypeInfo result;
217 if (operationType == KtTokens.EQ) {
218 result = visitAssignment(expression, context);
219 }
220 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
221 result = visitAssignmentOperation(expression, context);
222 }
223 else {
224 return facade.getTypeInfo(expression, context);
225 }
226 return components.dataFlowAnalyzer.checkType(result, expression, context);
227 }
228
229 @NotNull
230 protected KotlinTypeInfo visitAssignmentOperation(KtBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
231 //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
232 TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(
233 contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
234 ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE)
235 .replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
236
237 KtSimpleNameExpression operationSign = expression.getOperationReference();
238 IElementType operationType = operationSign.getReferencedNameElementType();
239 KtExpression leftOperand = expression.getLeft();
240 KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
241 KotlinType leftType = leftInfo.getType();
242
243 KtExpression right = expression.getRight();
244 KtExpression left = leftOperand == null ? null : deparenthesize(leftOperand);
245 if (right == null || left == null) {
246 temporary.commit();
247 return leftInfo.clearType();
248 }
249
250 if (leftType == null) {
251 KotlinTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
252 context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
253 temporary.commit();
254 return rightInfo.clearType();
255 }
256 ExpressionReceiver receiver = ExpressionReceiver.Companion.create(left, leftType, context.trace.getBindingContext());
257
258 // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
259 // Check for '+='
260 Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
261 TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(
262 context, "trace to check assignment operation like '+=' for", expression);
263 OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors =
264 components.callResolver.resolveBinaryCall(
265 context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope),
266 receiver, expression, name
267 );
268 KotlinType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors,
269 context.contextDependency);
270
271 OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors;
272 KotlinType binaryOperationType;
273 TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
274 context, "trace to check binary operation like '+' for", expression);
275 TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability");
276 boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right);
277 if (assignmentOperationType == null || lhsAssignable) {
278 // Check for '+'
279 Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
280 binaryOperationDescriptors = components.callResolver.resolveBinaryCall(
281 context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope),
282 receiver, expression, counterpartName
283 );
284 binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
285 }
286 else {
287 binaryOperationDescriptors = OverloadResolutionResultsImpl.nameNotFound();
288 binaryOperationType = null;
289 }
290
291 KotlinType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
292 KotlinTypeInfo rightInfo = leftInfo;
293 if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess()) {
294 // Both 'plus()' and 'plusAssign()' available => ambiguity
295 OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
296 context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
297 Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
298 for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
299 descriptors.add(resolvedCall.getResultingDescriptor());
300 }
301 rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
302 context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
303 }
304 else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
305 // There's 'plusAssign()', so we do a.plusAssign(b)
306 temporaryForAssignmentOperation.commit();
307 if (!KotlinTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) {
308 context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
309 }
310 }
311 else {
312 // There's only 'plus()', so we try 'a = a + b'
313 temporaryForBinaryOperation.commit();
314 context.trace.record(VARIABLE_REASSIGNMENT, expression);
315 if (left instanceof KtArrayAccessExpression) {
316 ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(
317 context.trace, "trace to resolve array set method for assignment", expression));
318 basic.resolveArrayAccessSetMethod((KtArrayAccessExpression) left, right, contextForResolve, context.trace);
319 }
320 rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
321 components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(rightInfo.getDataFlowInfo()));
322 basic.checkLValue(context.trace, context, leftOperand, right);
323 }
324 temporary.commit();
325 return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
326 }
327
328 @NotNull
329 protected KotlinTypeInfo visitAssignment(KtBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
330 final ExpressionTypingContext context =
331 contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(scope).replaceContextDependency(INDEPENDENT);
332 KtExpression leftOperand = expression.getLeft();
333 if (leftOperand instanceof KtAnnotatedExpression) {
334 // We will lose all annotations during deparenthesizing, so we have to resolve them right now
335 components.annotationResolver.resolveAnnotationsWithArguments(
336 scope, ((KtAnnotatedExpression) leftOperand).getAnnotationEntries(), context.trace
337 );
338 }
339 KtExpression left = deparenthesize(leftOperand);
340 KtExpression right = expression.getRight();
341 if (left instanceof KtArrayAccessExpression) {
342 KtArrayAccessExpression arrayAccessExpression = (KtArrayAccessExpression) left;
343 if (right == null) return TypeInfoFactoryKt.noTypeInfo(context);
344 KotlinTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
345 basic.checkLValue(context.trace, context, arrayAccessExpression, right);
346 return typeInfo.replaceType(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType));
347 }
348 KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
349 KotlinType leftType = leftInfo.getType();
350 DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
351 KotlinTypeInfo resultInfo;
352 if (right != null) {
353 resultInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
354 dataFlowInfo = resultInfo.getDataFlowInfo();
355 KotlinType rightType = resultInfo.getType();
356 if (left != null && leftType != null && rightType != null) {
357 DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, leftType, context);
358 DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context);
359 // We cannot say here anything new about rightValue except it has the same value as leftValue
360 resultInfo = resultInfo.replaceDataFlowInfo(dataFlowInfo.assign(leftValue, rightValue));
361 }
362 }
363 else {
364 resultInfo = leftInfo;
365 }
366 if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
367 basic.checkLValue(context.trace, context, leftOperand, right);
368 }
369 return resultInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(expression, contextWithExpectedType));
370 }
371
372
373 @Override
374 public KotlinTypeInfo visitExpression(@NotNull KtExpression expression, ExpressionTypingContext context) {
375 return facade.getTypeInfo(expression, context);
376 }
377
378 @Override
379 public KotlinTypeInfo visitKtElement(@NotNull KtElement element, ExpressionTypingContext context) {
380 context.trace.report(UNSUPPORTED.on(element, "in a block"));
381 return TypeInfoFactoryKt.noTypeInfo(context);
382 }
383
384 @Override
385 public KotlinTypeInfo visitWhileExpression(@NotNull KtWhileExpression expression, ExpressionTypingContext context) {
386 return controlStructures.visitWhileExpression(expression, context, true);
387 }
388
389 @Override
390 public KotlinTypeInfo visitDoWhileExpression(@NotNull KtDoWhileExpression expression, ExpressionTypingContext context) {
391 return controlStructures.visitDoWhileExpression(expression, context, true);
392 }
393
394 @Override
395 public KotlinTypeInfo visitForExpression(@NotNull KtForExpression expression, ExpressionTypingContext context) {
396 return controlStructures.visitForExpression(expression, context, true);
397 }
398
399 @Override
400 public KotlinTypeInfo visitAnnotatedExpression(
401 @NotNull KtAnnotatedExpression expression, ExpressionTypingContext data
402 ) {
403 return basic.visitAnnotatedExpression(expression, data, true);
404 }
405
406 @Override
407 public KotlinTypeInfo visitIfExpression(@NotNull KtIfExpression expression, ExpressionTypingContext context) {
408 return controlStructures.visitIfExpression(expression, context, true);
409 }
410
411 @Override
412 public KotlinTypeInfo visitWhenExpression(@NotNull KtWhenExpression expression, ExpressionTypingContext context) {
413 return patterns.visitWhenExpression(expression, context, true);
414 }
415
416 @Override
417 public KotlinTypeInfo visitBlockExpression(@NotNull KtBlockExpression expression, ExpressionTypingContext context) {
418 return components.expressionTypingServices.getBlockReturnedType(expression, context, true);
419 }
420
421 @Override
422 public KotlinTypeInfo visitLabeledExpression(@NotNull KtLabeledExpression expression, ExpressionTypingContext context) {
423 return basic.visitLabeledExpression(expression, context, true);
424 }
425 }