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.base.Function;
020    import com.google.common.collect.Sets;
021    import com.intellij.psi.tree.IElementType;
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.DeclarationDescriptor;
026    import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
027    import org.jetbrains.kotlin.descriptors.VariableDescriptor;
028    import org.jetbrains.kotlin.diagnostics.Errors;
029    import org.jetbrains.kotlin.lexer.JetTokens;
030    import org.jetbrains.kotlin.name.Name;
031    import org.jetbrains.kotlin.psi.*;
032    import org.jetbrains.kotlin.resolve.AnnotationResolver;
033    import org.jetbrains.kotlin.resolve.DescriptorUtils;
034    import org.jetbrains.kotlin.resolve.ModifiersChecker;
035    import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
036    import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
037    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
038    import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
039    import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
040    import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
041    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
042    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
043    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
044    import org.jetbrains.kotlin.resolve.scopes.WritableScope;
045    import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
046    import org.jetbrains.kotlin.types.JetType;
047    import org.jetbrains.kotlin.types.TypeUtils;
048    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
049    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
050    
051    import java.util.Collection;
052    
053    import static org.jetbrains.kotlin.diagnostics.Errors.*;
054    import static org.jetbrains.kotlin.psi.JetPsiUtil.deparenthesizeWithResolutionStrategy;
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 WritableScope 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 WritableScope 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 static JetType checkAssignmentType(
087                @Nullable JetType assignmentType,
088                @NotNull JetBinaryExpression 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 DataFlowUtils.checkStatementType(expression, context);
097        }
098    
099        @Override
100        public JetTypeInfo visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, ExpressionTypingContext context) {
101            components.localClassifierAnalyzer.processClassOrObject(
102                    components.globalContext,
103                    scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), declaration,
104                    components.additionalCheckerProvider,
105                    components.dynamicTypesSettings);
106            return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(declaration, context), context);
107        }
108    
109        @Override
110        public JetTypeInfo visitProperty(@NotNull JetProperty property, ExpressionTypingContext typingContext) {
111            ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT).replaceScope(scope);
112            JetTypeReference receiverTypeRef = property.getReceiverTypeReference();
113            if (receiverTypeRef != null) {
114                context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef));
115            }
116    
117            JetPropertyAccessor getter = property.getGetter();
118            if (getter != null) {
119                context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter));
120            }
121    
122            JetPropertyAccessor setter = property.getSetter();
123            if (setter != null) {
124                context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter));
125            }
126    
127            JetExpression delegateExpression = property.getDelegateExpression();
128            if (delegateExpression != null) {
129                components.expressionTypingServices.getTypeInfo(delegateExpression, context);
130                context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate()));
131            }
132    
133            for (JetTypeParameter typeParameter : property.getTypeParameters()) {
134                AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(typeParameter, context.trace);
135            }
136    
137            VariableDescriptor propertyDescriptor = components.descriptorResolver.
138                    resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace);
139            AnnotationResolver.resolveAnnotationsArguments(propertyDescriptor.getType().getAnnotations());
140            JetExpression initializer = property.getInitializer();
141            JetTypeInfo typeInfo;
142            if (initializer != null) {
143                JetType outType = propertyDescriptor.getType();
144                typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
145                DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
146                JetType type = typeInfo.getType();
147                // At this moment we do not take initializer value into account if type is given for a property
148                // We can comment first part of this condition to take them into account, like here: var s: String? = "xyz"
149                // In this case s will be not-nullable until it is changed
150                if (property.getTypeReference() == null && type != null) {
151                    DataFlowValue variableDataFlowValue = DataFlowValueFactory.createDataFlowValue(
152                            propertyDescriptor, context.trace.getBindingContext(),
153                            DescriptorUtils.getContainingModuleOrNull(scope.getContainingDeclaration()));
154                    DataFlowValue initializerDataFlowValue = DataFlowValueFactory.createDataFlowValue(initializer, type, context);
155                    // We cannot say here anything new about initializerDataFlowValue
156                    // except it has the same value as variableDataFlowValue
157                    typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.assign(variableDataFlowValue, initializerDataFlowValue));
158                }
159            }
160            else {
161                typeInfo = TypeInfoFactoryPackage.noTypeInfo(context);
162            }
163    
164            {
165                VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName());
166                ExpressionTypingUtils.checkVariableShadowing(context, propertyDescriptor, olderVariable);
167            }
168    
169            scope.addVariableDescriptor(propertyDescriptor);
170            ModifiersChecker.create(context.trace, components.additionalCheckerProvider).checkModifiersForLocalDeclaration(property, propertyDescriptor);
171            return typeInfo.replaceType(DataFlowUtils.checkStatementType(property, context));
172        }
173    
174        @Override
175        public JetTypeInfo visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, ExpressionTypingContext context) {
176            components.annotationResolver.resolveAnnotationsWithArguments(
177                    scope, multiDeclaration.getModifierList(), context.trace);
178    
179            JetExpression initializer = multiDeclaration.getInitializer();
180            if (initializer == null) {
181                context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration));
182                return TypeInfoFactoryPackage.noTypeInfo(context);
183            }
184            ExpressionReceiver expressionReceiver = ExpressionTypingUtils.getExpressionReceiver(
185                    facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
186            JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context);
187            if (expressionReceiver == null) {
188                return TypeInfoFactoryPackage.noTypeInfo(context);
189            }
190            components.multiDeclarationResolver.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
191            return typeInfo.replaceType(DataFlowUtils.checkStatementType(multiDeclaration, context));
192        }
193    
194        @Override
195        public JetTypeInfo visitNamedFunction(@NotNull JetNamedFunction function, ExpressionTypingContext context) {
196            return functions.visitNamedFunction(function, context, true, scope);
197        }
198    
199        @Override
200        public JetTypeInfo visitClass(@NotNull JetClass klass, ExpressionTypingContext context) {
201            components.localClassifierAnalyzer.processClassOrObject(
202                    components.globalContext,
203                    scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), klass,
204                    components.additionalCheckerProvider,
205                    components.dynamicTypesSettings);
206            return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(klass, context), context);
207        }
208    
209        @Override
210        public JetTypeInfo visitTypedef(@NotNull JetTypedef typedef, ExpressionTypingContext context) {
211            context.trace.report(UNSUPPORTED.on(typedef, "Typedefs are not supported"));
212            return super.visitTypedef(typedef, context);
213        }
214    
215        @Override
216        public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) {
217            return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(dcl, context), context);
218        }
219    
220        @Override
221        public JetTypeInfo visitBinaryExpression(@NotNull JetBinaryExpression expression, ExpressionTypingContext context) {
222            JetSimpleNameExpression operationSign = expression.getOperationReference();
223            IElementType operationType = operationSign.getReferencedNameElementType();
224            JetTypeInfo result;
225            if (operationType == JetTokens.EQ) {
226                result = visitAssignment(expression, context);
227            }
228            else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
229                result = visitAssignmentOperation(expression, context);
230            }
231            else {
232                return facade.getTypeInfo(expression, context);
233            }
234            return DataFlowUtils.checkType(result, expression, context);
235        }
236    
237        @NotNull
238        protected JetTypeInfo visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
239            //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
240            TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(
241                    contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
242            ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE)
243                    .replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
244    
245            JetSimpleNameExpression operationSign = expression.getOperationReference();
246            IElementType operationType = operationSign.getReferencedNameElementType();
247            JetExpression leftOperand = expression.getLeft();
248            JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
249            JetType leftType = leftInfo.getType();
250    
251            JetExpression right = expression.getRight();
252            JetExpression left = leftOperand == null ? null : JetPsiUtil.deparenthesize(leftOperand);
253            if (right == null || left == null) {
254                temporary.commit();
255                return leftInfo.clearType();
256            }
257    
258            if (leftType == null) {
259                JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
260                context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
261                temporary.commit();
262                return rightInfo.clearType();
263            }
264            ExpressionReceiver receiver = new ExpressionReceiver(left, leftType);
265    
266            // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
267            // Check for '+='
268            Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
269            TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(
270                    context, "trace to check assignment operation like '+=' for", expression);
271            OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors =
272                    components.callResolver.resolveBinaryCall(
273                            context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope),
274                            receiver, expression, name
275                    );
276            JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors,
277                                                                                             context.contextDependency);
278    
279            OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors;
280            JetType binaryOperationType;
281            TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
282                    context, "trace to check binary operation like '+' for", expression);
283            TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability");
284            boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right);
285            if (assignmentOperationType == null || lhsAssignable) {
286                // Check for '+'
287                Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
288                binaryOperationDescriptors = components.callResolver.resolveBinaryCall(
289                        context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope),
290                        receiver, expression, counterpartName
291                );
292                binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
293            }
294            else {
295                binaryOperationDescriptors = OverloadResolutionResultsImpl.nameNotFound();
296                binaryOperationType = null;
297            }
298    
299            JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
300            JetTypeInfo rightInfo = leftInfo;
301            if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess()) {
302                // Both 'plus()' and 'plusAssign()' available => ambiguity
303                OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
304                context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
305                Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
306                for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
307                    descriptors.add(resolvedCall.getResultingDescriptor());
308                }
309                rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
310                context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
311            }
312            else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
313                // There's 'plusAssign()', so we do a.plusAssign(b)
314                temporaryForAssignmentOperation.commit();
315                if (!JetTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) {
316                    context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
317                }
318            }
319            else {
320                // There's only 'plus()', so we try 'a = a + b'
321                temporaryForBinaryOperation.commit();
322                context.trace.record(VARIABLE_REASSIGNMENT, expression);
323                if (left instanceof JetArrayAccessExpression) {
324                    ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(
325                            context.trace, "trace to resolve array set method for assignment", expression));
326                    basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace);
327                }
328                rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
329                DataFlowUtils.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(rightInfo.getDataFlowInfo()));
330                basic.checkLValue(context.trace, context, leftOperand, right);
331            }
332            temporary.commit();
333            return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
334        }
335    
336        @NotNull
337        protected JetTypeInfo visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
338            final ExpressionTypingContext context =
339                    contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(scope).replaceContextDependency(INDEPENDENT);
340            JetExpression leftOperand = expression.getLeft();
341            JetExpression left = deparenthesizeWithResolutionStrategy(leftOperand, new Function<JetTypeReference, Void>() {
342                @Override
343                public Void apply(JetTypeReference reference) {
344                    components.typeResolver.resolveType(context.scope, reference, context.trace, true);
345                    return null;
346                }
347            });
348            JetExpression right = expression.getRight();
349            if (left instanceof JetArrayAccessExpression) {
350                JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
351                if (right == null) return TypeInfoFactoryPackage.noTypeInfo(context);
352                JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
353                basic.checkLValue(context.trace, context, arrayAccessExpression, right);
354                return typeInfo.replaceType(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType));
355            }
356            JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
357            JetType leftType = leftInfo.getType();
358            DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
359            JetTypeInfo resultInfo;
360            if (right != null) {
361                resultInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
362                dataFlowInfo = resultInfo.getDataFlowInfo();
363                JetType rightType = resultInfo.getType();
364                if (left != null && leftType != null && rightType != null) {
365                    DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, leftType, context);
366                    DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context);
367                    // We cannot say here anything new about rightValue except it has the same value as leftValue
368                    resultInfo = resultInfo.replaceDataFlowInfo(dataFlowInfo.assign(leftValue, rightValue));
369                }
370            }
371            else {
372                resultInfo = leftInfo;
373            }
374            if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
375                basic.checkLValue(context.trace, context, leftOperand, right);
376            }
377            return resultInfo.replaceType(DataFlowUtils.checkStatementType(expression, contextWithExpectedType));
378        }
379    
380    
381        @Override
382        public JetTypeInfo visitExpression(@NotNull JetExpression expression, ExpressionTypingContext context) {
383            return facade.getTypeInfo(expression, context);
384        }
385    
386        @Override
387        public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext context) {
388            context.trace.report(UNSUPPORTED.on(element, "in a block"));
389            return TypeInfoFactoryPackage.noTypeInfo(context);
390        }
391    
392        @Override
393        public JetTypeInfo visitWhileExpression(@NotNull JetWhileExpression expression, ExpressionTypingContext context) {
394            return controlStructures.visitWhileExpression(expression, context, true);
395        }
396    
397        @Override
398        public JetTypeInfo visitDoWhileExpression(@NotNull JetDoWhileExpression expression, ExpressionTypingContext context) {
399            return controlStructures.visitDoWhileExpression(expression, context, true);
400        }
401    
402        @Override
403        public JetTypeInfo visitForExpression(@NotNull JetForExpression expression, ExpressionTypingContext context) {
404            return controlStructures.visitForExpression(expression, context, true);
405        }
406    
407        @Override
408        public JetTypeInfo visitAnnotatedExpression(
409                @NotNull JetAnnotatedExpression expression, ExpressionTypingContext data
410        ) {
411            return basic.visitAnnotatedExpression(expression, data, true);
412        }
413    
414        @Override
415        public JetTypeInfo visitIfExpression(@NotNull JetIfExpression expression, ExpressionTypingContext context) {
416            return controlStructures.visitIfExpression(expression, context, true);
417        }
418    
419        @Override
420        public JetTypeInfo visitWhenExpression(@NotNull JetWhenExpression expression, ExpressionTypingContext context) {
421            return patterns.visitWhenExpression(expression, context, true);
422        }
423    
424        @Override
425        public JetTypeInfo visitBlockExpression(@NotNull JetBlockExpression expression, ExpressionTypingContext context) {
426            return components.expressionTypingServices.getBlockReturnedType(expression, context, true);
427        }
428    
429        @Override
430        public JetTypeInfo visitLabeledExpression(@NotNull JetLabeledExpression expression, ExpressionTypingContext context) {
431            return basic.visitLabeledExpression(expression, context, true);
432        }
433    }