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