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    }