001    /*
002     * Copyright 2010-2013 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.jet.lang.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.jet.lang.descriptors.DeclarationDescriptor;
024    import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
025    import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
026    import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
027    import org.jetbrains.jet.lang.diagnostics.Errors;
028    import org.jetbrains.jet.lang.psi.*;
029    import org.jetbrains.jet.lang.resolve.*;
030    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
031    import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache;
032    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
033    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
034    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
035    import org.jetbrains.jet.lang.resolve.name.Name;
036    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
037    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
038    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
039    import org.jetbrains.jet.lang.types.JetType;
040    import org.jetbrains.jet.lang.types.JetTypeInfo;
041    import org.jetbrains.jet.lang.types.TypeUtils;
042    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
043    import org.jetbrains.jet.lexer.JetTokens;
044    
045    import java.util.Collection;
046    
047    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
048    import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET;
049    import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT;
050    import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
051    import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
052    import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
053    
054    @SuppressWarnings("SuspiciousMethodCalls")
055    public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisitor {
056        private final WritableScope scope;
057        private final BasicExpressionTypingVisitor basic;
058        private final ControlStructureTypingVisitor controlStructures;
059        private final PatternMatchingTypingVisitor patterns;
060    
061        public ExpressionTypingVisitorForStatements(
062                @NotNull ExpressionTypingInternals facade,
063                @NotNull WritableScope scope,
064                BasicExpressionTypingVisitor basic,
065                @NotNull ControlStructureTypingVisitor controlStructures,
066                @NotNull PatternMatchingTypingVisitor patterns) {
067            super(facade);
068            this.scope = scope;
069            this.basic = basic;
070            this.controlStructures = controlStructures;
071            this.patterns = patterns;
072        }
073    
074        @Nullable
075        private static JetType checkAssignmentType(
076                @Nullable JetType assignmentType,
077                @NotNull JetBinaryExpression expression,
078                @NotNull ExpressionTypingContext context
079        ) {
080            if (assignmentType != null && !KotlinBuiltIns.getInstance().isUnit(assignmentType) && !noExpectedType(context.expectedType) &&
081                TypeUtils.equalTypes(context.expectedType, assignmentType)) {
082                context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType));
083                return null;
084            }
085            return DataFlowUtils.checkStatementType(expression, context);
086        }
087    
088        @Override
089        public JetTypeInfo visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, ExpressionTypingContext context) {
090            TopDownAnalyzer.processClassOrObject(
091                    components.globalContext,
092                    scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), declaration,
093                    components.additionalCheckerProvider);
094            return DataFlowUtils.checkStatementType(declaration, context, context.dataFlowInfo);
095        }
096    
097        @Override
098        public JetTypeInfo visitProperty(@NotNull JetProperty property, ExpressionTypingContext typingContext) {
099            ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT).replaceScope(scope);
100            JetTypeReference receiverTypeRef = property.getReceiverTypeRef();
101            if (receiverTypeRef != null) {
102                context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef));
103            }
104    
105            JetPropertyAccessor getter = property.getGetter();
106            if (getter != null) {
107                context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter));
108            }
109    
110            JetPropertyAccessor setter = property.getSetter();
111            if (setter != null) {
112                context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter));
113            }
114    
115            JetExpression delegateExpression = property.getDelegateExpression();
116            if (delegateExpression != null) {
117                components.expressionTypingServices.getTypeInfo(delegateExpression, context);
118                context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate()));
119            }
120    
121            for (JetTypeParameter typeParameter : property.getTypeParameters()) {
122                AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(typeParameter, context.trace);
123            }
124    
125            VariableDescriptor propertyDescriptor = components.expressionTypingServices.getDescriptorResolver().
126                    resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace);
127            JetExpression initializer = property.getInitializer();
128            DataFlowInfo dataFlowInfo = context.dataFlowInfo;
129            if (initializer != null) {
130                JetType outType = propertyDescriptor.getType();
131                JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
132                dataFlowInfo = typeInfo.getDataFlowInfo();
133            }
134    
135            {
136                VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName());
137                ExpressionTypingUtils.checkVariableShadowing(context, propertyDescriptor, olderVariable);
138            }
139    
140            scope.addVariableDescriptor(propertyDescriptor);
141            ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor);
142            return DataFlowUtils.checkStatementType(property, context, dataFlowInfo);
143        }
144    
145        @Override
146        public JetTypeInfo visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, ExpressionTypingContext context) {
147            components.expressionTypingServices.getAnnotationResolver().resolveAnnotationsWithArguments(
148                    scope, multiDeclaration.getModifierList(), context.trace);
149    
150            JetExpression initializer = multiDeclaration.getInitializer();
151            if (initializer == null) {
152                context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration));
153                return JetTypeInfo.create(null, context.dataFlowInfo);
154            }
155            ExpressionReceiver expressionReceiver = ExpressionTypingUtils.getExpressionReceiver(
156                    facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
157            DataFlowInfo dataFlowInfo = facade.getTypeInfo(initializer, context).getDataFlowInfo();
158            if (expressionReceiver == null) {
159                return JetTypeInfo.create(null, dataFlowInfo);
160            }
161            components.expressionTypingUtils.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
162            return DataFlowUtils.checkStatementType(multiDeclaration, context, dataFlowInfo);
163        }
164    
165        @Override
166        public JetTypeInfo visitNamedFunction(@NotNull JetNamedFunction function, ExpressionTypingContext context) {
167            SimpleFunctionDescriptor functionDescriptor = components.expressionTypingServices.getDescriptorResolver().
168                    resolveFunctionDescriptorWithAnnotationArguments(
169                            scope.getContainingDeclaration(), scope, function, context.trace, context.dataFlowInfo);
170    
171            scope.addFunctionDescriptor(functionDescriptor);
172            JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
173            components.expressionTypingServices.checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace);
174    
175            components.expressionTypingServices.resolveValueParameters(function.getValueParameters(), functionDescriptor.getValueParameters(),
176                                                                    scope, context.dataFlowInfo, context.trace, /* needCompleteAnalysis = */ true);
177    
178            ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(function, functionDescriptor);
179            if (!function.hasBody()) {
180                context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
181            }
182            return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo);
183        }
184    
185        @Override
186        public JetTypeInfo visitClass(@NotNull JetClass klass, ExpressionTypingContext context) {
187            TopDownAnalyzer.processClassOrObject(
188                    components.globalContext,
189                    scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), klass,
190                    components.additionalCheckerProvider);
191            return DataFlowUtils.checkStatementType(klass, context, context.dataFlowInfo);
192        }
193    
194        @Override
195        public JetTypeInfo visitTypedef(@NotNull JetTypedef typedef, ExpressionTypingContext context) {
196            context.trace.report(UNSUPPORTED.on(typedef, "Typedefs are not supported"));
197            return super.visitTypedef(typedef, context);
198        }
199    
200        @Override
201        public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) {
202            return DataFlowUtils.checkStatementType(dcl, context, context.dataFlowInfo);
203        }
204    
205        @Override
206        public JetTypeInfo visitBinaryExpression(@NotNull JetBinaryExpression expression, ExpressionTypingContext context) {
207            JetSimpleNameExpression operationSign = expression.getOperationReference();
208            IElementType operationType = operationSign.getReferencedNameElementType();
209            JetTypeInfo result;
210            if (operationType == JetTokens.EQ) {
211                result = visitAssignment(expression, context);
212            }
213            else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
214                result = visitAssignmentOperation(expression, context);
215            }
216            else {
217                return facade.getTypeInfo(expression, context);
218            }
219            return DataFlowUtils.checkType(result.getType(), expression, context, result.getDataFlowInfo());
220        }
221    
222        @NotNull
223        protected JetTypeInfo visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
224            //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
225            TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(
226                    contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
227            ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE)
228                    .replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
229    
230            JetSimpleNameExpression operationSign = expression.getOperationReference();
231            IElementType operationType = operationSign.getReferencedNameElementType();
232            JetExpression leftOperand = expression.getLeft();
233            JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
234            JetType leftType = leftInfo.getType();
235            DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
236    
237            JetExpression right = expression.getRight();
238            JetExpression left = leftOperand == null ? null : JetPsiUtil.deparenthesize(leftOperand);
239            if (right == null || left == null) {
240                temporary.commit();
241                return JetTypeInfo.create(null, dataFlowInfo);
242            }
243    
244            if (leftType == null) {
245                dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
246                context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
247                temporary.commit();
248                return JetTypeInfo.create(null, dataFlowInfo);
249            }
250            ExpressionReceiver receiver = new ExpressionReceiver(left, leftType);
251    
252            // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
253            // Check for '+='
254            Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
255            TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(
256                    context, "trace to check assignment operation like '+=' for", expression);
257            OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors =
258                    components.callResolver.resolveBinaryCall(
259                            context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope),
260                            receiver, expression, name
261                    );
262            JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors,
263                                                                                             context.contextDependency);
264    
265            // Check for '+'
266            Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
267            TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
268                    context, "trace to check binary operation like '+' for", expression);
269            OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors = components.callResolver.resolveBinaryCall(
270                    context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope),
271                    receiver, expression, counterpartName
272            );
273            JetType binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
274    
275            JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
276            if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess()) {
277                // Both 'plus()' and 'plusAssign()' available => ambiguity
278                OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
279                context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
280                Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
281                for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
282                    descriptors.add(resolvedCall.getResultingDescriptor());
283                }
284                dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
285                context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
286            }
287            else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
288                // There's 'plusAssign()', so we do a.plusAssign(b)
289                temporaryForAssignmentOperation.commit();
290                if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) {
291                    context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
292                }
293            }
294            else {
295                // There's only 'plus()', so we try 'a = a + b'
296                temporaryForBinaryOperation.commit();
297                context.trace.record(VARIABLE_REASSIGNMENT, expression);
298                if (left instanceof JetArrayAccessExpression) {
299                    ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(
300                            context.trace, "trace to resolve array set method for assignment", expression));
301                    basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace);
302                }
303                dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
304                DataFlowUtils.checkType(binaryOperationType, expression, leftType, dataFlowInfo, context.trace);
305                BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
306            }
307            temporary.commit();
308            return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo);
309        }
310    
311        @NotNull
312        protected JetTypeInfo visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
313            ExpressionTypingContext context =
314                    contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(scope).replaceContextDependency(INDEPENDENT);
315            JetExpression leftOperand = expression.getLeft();
316            JetExpression left = components.expressionTypingServices.deparenthesizeWithTypeResolution(leftOperand, context);
317            JetExpression right = expression.getRight();
318            if (left instanceof JetArrayAccessExpression) {
319                JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
320                if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo);
321                JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
322                BasicExpressionTypingVisitor.checkLValue(context.trace, arrayAccessExpression);
323                return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType),
324                                          typeInfo.getDataFlowInfo());
325            }
326            JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
327            JetType leftType = leftInfo.getType();
328            DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
329            if (right != null) {
330                JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
331                dataFlowInfo = rightInfo.getDataFlowInfo();
332            }
333            if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
334                BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
335            }
336            return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo);
337        }
338    
339    
340        @Override
341        public JetTypeInfo visitExpression(@NotNull JetExpression expression, ExpressionTypingContext context) {
342            return facade.getTypeInfo(expression, context);
343        }
344    
345        @Override
346        public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext context) {
347            context.trace.report(UNSUPPORTED.on(element, "in a block"));
348            return JetTypeInfo.create(null, context.dataFlowInfo);
349        }
350    
351        @Override
352        public JetTypeInfo visitWhileExpression(@NotNull JetWhileExpression expression, ExpressionTypingContext context) {
353            return controlStructures.visitWhileExpression(expression, context, true);
354        }
355    
356        @Override
357        public JetTypeInfo visitDoWhileExpression(@NotNull JetDoWhileExpression expression, ExpressionTypingContext context) {
358            return controlStructures.visitDoWhileExpression(expression, context, true);
359        }
360    
361        @Override
362        public JetTypeInfo visitForExpression(@NotNull JetForExpression expression, ExpressionTypingContext context) {
363            return controlStructures.visitForExpression(expression, context, true);
364        }
365    
366        @Override
367        public JetTypeInfo visitAnnotatedExpression(
368                @NotNull JetAnnotatedExpression expression, ExpressionTypingContext data
369        ) {
370            return basic.visitAnnotatedExpression(expression, data, true);
371        }
372    
373        @Override
374        public JetTypeInfo visitIfExpression(@NotNull JetIfExpression expression, ExpressionTypingContext context) {
375            return controlStructures.visitIfExpression(expression, context, true);
376        }
377    
378        @Override
379        public JetTypeInfo visitWhenExpression(@NotNull JetWhenExpression expression, ExpressionTypingContext context) {
380            return patterns.visitWhenExpression(expression, context, true);
381        }
382    
383        @Override
384        public JetTypeInfo visitBlockExpression(@NotNull JetBlockExpression expression, ExpressionTypingContext context) {
385            return components.expressionTypingServices.getBlockReturnedType(expression, context, true);
386        }
387    
388        @Override
389        public JetTypeInfo visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, ExpressionTypingContext context) {
390            return basic.visitParenthesizedExpression(expression, context, true);
391        }
392    
393        @Override
394        public JetTypeInfo visitLabeledExpression(@NotNull JetLabeledExpression expression, ExpressionTypingContext context) {
395            return basic.visitLabeledExpression(expression, context, true);
396        }
397    }