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