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    }