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    }