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.intellij.psi.tree.IElementType;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
023    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
024    import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
025    import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
026    import org.jetbrains.kotlin.lexer.KtTokens;
027    import org.jetbrains.kotlin.psi.*;
028    import org.jetbrains.kotlin.resolve.*;
029    import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
030    import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
031    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
032    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
033    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
034    import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
035    import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
036    import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
037    import org.jetbrains.kotlin.types.ErrorUtils;
038    import org.jetbrains.kotlin.types.KotlinType;
039    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
040    
041    import java.util.Iterator;
042    import java.util.List;
043    
044    import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
045    import static org.jetbrains.kotlin.types.TypeUtils.UNIT_EXPECTED_TYPE;
046    import static org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
047    
048    public class ExpressionTypingServices {
049    
050        private final ExpressionTypingFacade expressionTypingFacade;
051        private final ExpressionTypingComponents expressionTypingComponents;
052    
053        @NotNull private final AnnotationChecker annotationChecker;
054        @NotNull private final StatementFilter statementFilter;
055    
056        public ExpressionTypingServices(
057                @NotNull ExpressionTypingComponents components,
058                @NotNull AnnotationChecker annotationChecker,
059                @NotNull StatementFilter statementFilter,
060                @NotNull ExpressionTypingVisitorDispatcher.ForDeclarations facade
061        ) {
062            this.expressionTypingComponents = components;
063            this.annotationChecker = annotationChecker;
064            this.statementFilter = statementFilter;
065            this.expressionTypingFacade = facade;
066        }
067    
068        @NotNull public StatementFilter getStatementFilter() {
069            return statementFilter;
070        }
071    
072        @NotNull
073        public KotlinType safeGetType(
074                @NotNull LexicalScope scope,
075                @NotNull KtExpression expression,
076                @NotNull KotlinType expectedType,
077                @NotNull DataFlowInfo dataFlowInfo,
078                @NotNull BindingTrace trace
079        ) {
080            KotlinType type = getType(scope, expression, expectedType, dataFlowInfo, trace);
081    
082            return type != null ? type : ErrorUtils.createErrorType("Type for " + expression.getText());
083        }
084    
085        @NotNull
086        public KotlinTypeInfo getTypeInfo(
087                @NotNull LexicalScope scope,
088                @NotNull KtExpression expression,
089                @NotNull KotlinType expectedType,
090                @NotNull DataFlowInfo dataFlowInfo,
091                @NotNull BindingTrace trace,
092                boolean isStatement
093        ) {
094            ExpressionTypingContext context = ExpressionTypingContext.newContext(
095                    trace, scope, dataFlowInfo, expectedType
096            );
097            return expressionTypingFacade.getTypeInfo(expression, context, isStatement);
098        }
099    
100        @NotNull
101        public KotlinTypeInfo getTypeInfo(@NotNull KtExpression expression, @NotNull ResolutionContext resolutionContext) {
102            return expressionTypingFacade.getTypeInfo(expression, ExpressionTypingContext.newContext(resolutionContext));
103        }
104    
105        @Nullable
106        public KotlinType getType(
107                @NotNull LexicalScope scope,
108                @NotNull KtExpression expression,
109                @NotNull KotlinType expectedType,
110                @NotNull DataFlowInfo dataFlowInfo,
111                @NotNull BindingTrace trace
112        ) {
113            return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace, false).getType();
114        }
115    
116        /////////////////////////////////////////////////////////
117    
118        public void checkFunctionReturnType(
119                @NotNull LexicalScope functionInnerScope,
120                @NotNull KtDeclarationWithBody function,
121                @NotNull FunctionDescriptor functionDescriptor,
122                @NotNull DataFlowInfo dataFlowInfo,
123                @Nullable KotlinType expectedReturnType,
124                BindingTrace trace
125        ) {
126            if (expectedReturnType == null) {
127                expectedReturnType = functionDescriptor.getReturnType();
128                if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
129                    expectedReturnType = NO_EXPECTED_TYPE;
130                }
131            }
132            checkFunctionReturnType(function, ExpressionTypingContext.newContext(
133                    trace,
134                    functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE
135            ));
136        }
137    
138        /*package*/ void checkFunctionReturnType(KtDeclarationWithBody function, ExpressionTypingContext context) {
139            KtExpression bodyExpression = function.getBodyExpression();
140            if (bodyExpression == null) return;
141    
142            boolean blockBody = function.hasBlockBody();
143            ExpressionTypingContext newContext =
144                    blockBody
145                    ? context.replaceExpectedType(NO_EXPECTED_TYPE)
146                    : context;
147    
148            expressionTypingFacade.getTypeInfo(bodyExpression, newContext, blockBody);
149        }
150    
151        @NotNull
152        public KotlinTypeInfo getBlockReturnedType(KtBlockExpression expression, ExpressionTypingContext context, boolean isStatement) {
153            return getBlockReturnedType(expression, isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION, context);
154        }
155    
156        @NotNull
157        public KotlinTypeInfo getBlockReturnedType(
158                @NotNull KtBlockExpression expression,
159                @NotNull CoercionStrategy coercionStrategyForLastExpression,
160                @NotNull ExpressionTypingContext context
161        ) {
162            List<KtExpression> block = StatementFilterKt.filterStatements(statementFilter, expression);
163    
164            DeclarationDescriptor containingDescriptor = context.scope.getOwnerDescriptor();
165            LexicalWritableScope scope = new LexicalWritableScope(context.scope, containingDescriptor, false, null,
166                                                                  new TraceBasedRedeclarationHandler(context.trace), LexicalScopeKind.CODE_BLOCK);
167            scope.changeLockLevel(LexicalWritableScope.LockLevel.BOTH);
168    
169            KotlinTypeInfo r;
170            if (block.isEmpty()) {
171                r = expressionTypingComponents.dataFlowAnalyzer
172                        .createCheckedTypeInfo(expressionTypingComponents.builtIns.getUnitType(), context, expression);
173            }
174            else {
175                r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression,
176                                                          context.replaceStatementFilter(statementFilter));
177            }
178            scope.changeLockLevel(LexicalWritableScope.LockLevel.READING);
179    
180            if (containingDescriptor instanceof ScriptDescriptor) {
181                context.trace.record(BindingContext.SCRIPT_SCOPE, (ScriptDescriptor) containingDescriptor, scope);
182            }
183    
184            return r;
185        }
186    
187        @NotNull
188        public KotlinType getBodyExpressionType(
189                @NotNull BindingTrace trace,
190                @NotNull LexicalScope outerScope,
191                @NotNull DataFlowInfo dataFlowInfo,
192                @NotNull KtDeclarationWithBody function,
193                @NotNull FunctionDescriptor functionDescriptor
194        ) {
195            KtExpression bodyExpression = function.getBodyExpression();
196            assert bodyExpression != null;
197            LexicalScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
198    
199            ExpressionTypingContext context = ExpressionTypingContext.newContext(
200                    trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE
201            );
202            KotlinTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
203    
204            KotlinType type = typeInfo.getType();
205            if (type != null) {
206                return type;
207            }
208            else {
209                return ErrorUtils.createErrorType("Error function type");
210            }
211        }
212    
213        /**
214         * Visits block statements propagating data flow information from the first to the last.
215         * Determines block returned type and data flow information at the end of the block AND
216         * at the nearest jump point from the block beginning.
217         */
218        /*package*/ KotlinTypeInfo getBlockReturnedTypeWithWritableScope(
219                @NotNull LexicalWritableScope scope,
220                @NotNull List<? extends KtElement> block,
221                @NotNull CoercionStrategy coercionStrategyForLastExpression,
222                @NotNull ExpressionTypingContext context
223        ) {
224            if (block.isEmpty()) {
225                return TypeInfoFactoryKt.createTypeInfo(expressionTypingComponents.builtIns.getUnitType(), context);
226            }
227    
228            ExpressionTypingInternals blockLevelVisitor = new ExpressionTypingVisitorDispatcher.ForBlock(
229                    expressionTypingComponents, annotationChecker, scope);
230            ExpressionTypingContext newContext = context.replaceScope(scope).replaceExpectedType(NO_EXPECTED_TYPE);
231    
232            KotlinTypeInfo result = TypeInfoFactoryKt.noTypeInfo(context);
233            // Jump point data flow info
234            DataFlowInfo beforeJumpInfo = newContext.dataFlowInfo;
235            boolean jumpOutPossible = false;
236            for (Iterator<? extends KtElement> iterator = block.iterator(); iterator.hasNext(); ) {
237                KtElement statement = iterator.next();
238                if (!(statement instanceof KtExpression)) {
239                    continue;
240                }
241                KtExpression statementExpression = (KtExpression) statement;
242                if (!iterator.hasNext()) {
243                    result = getTypeOfLastExpressionInBlock(
244                            statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression,
245                            blockLevelVisitor);
246                    if (result.getType() != null && statementExpression.getParent() instanceof KtBlockExpression) {
247                        DataFlowValue lastExpressionValue = DataFlowValueFactory.createDataFlowValue(
248                                statementExpression, result.getType(), context);
249                        DataFlowValue blockExpressionValue = DataFlowValueFactory.createDataFlowValue(
250                                (KtBlockExpression) statementExpression.getParent(), result.getType(), context);
251                        result = result.replaceDataFlowInfo(result.getDataFlowInfo().assign(blockExpressionValue, lastExpressionValue));
252                    }
253                }
254                else {
255                    result = blockLevelVisitor
256                            .getTypeInfo(statementExpression, newContext.replaceContextDependency(ContextDependency.INDEPENDENT), true);
257                }
258    
259                DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
260                // If jump is not possible, we take new data flow info before jump
261                if (!jumpOutPossible) {
262                    beforeJumpInfo = result.getJumpFlowInfo();
263                    jumpOutPossible = result.getJumpOutPossible();
264                }
265                if (newDataFlowInfo != context.dataFlowInfo) {
266                    newContext = newContext.replaceDataFlowInfo(newDataFlowInfo);
267                    // We take current data flow info if jump there is not possible
268                }
269                blockLevelVisitor = new ExpressionTypingVisitorDispatcher.ForBlock(expressionTypingComponents, annotationChecker, scope);
270            }
271            return result.replaceJumpOutPossible(jumpOutPossible).replaceJumpFlowInfo(beforeJumpInfo);
272        }
273    
274        private KotlinTypeInfo getTypeOfLastExpressionInBlock(
275                @NotNull KtExpression statementExpression,
276                @NotNull ExpressionTypingContext context,
277                @NotNull CoercionStrategy coercionStrategyForLastExpression,
278                @NotNull ExpressionTypingInternals blockLevelVisitor
279        ) {
280            if (context.expectedType != NO_EXPECTED_TYPE) {
281                KotlinType expectedType;
282                if (context.expectedType == UNIT_EXPECTED_TYPE ||//the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)'
283                    (coercionStrategyForLastExpression == COERCION_TO_UNIT && KotlinBuiltIns.isUnit(context.expectedType))) {
284                    expectedType = UNIT_EXPECTED_TYPE;
285                }
286                else {
287                    expectedType = context.expectedType;
288                }
289    
290                return blockLevelVisitor.getTypeInfo(statementExpression, context.replaceExpectedType(expectedType), true);
291            }
292            KotlinTypeInfo result = blockLevelVisitor.getTypeInfo(statementExpression, context, true);
293            if (coercionStrategyForLastExpression == COERCION_TO_UNIT) {
294                boolean mightBeUnit = false;
295                if (statementExpression instanceof KtDeclaration) {
296                    mightBeUnit = true;
297                }
298                if (statementExpression instanceof KtBinaryExpression) {
299                    KtBinaryExpression binaryExpression = (KtBinaryExpression) statementExpression;
300                    IElementType operationType = binaryExpression.getOperationToken();
301                    //noinspection SuspiciousMethodCalls
302                    if (operationType == KtTokens.EQ || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
303                        mightBeUnit = true;
304                    }
305                }
306                if (mightBeUnit) {
307                    // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments,
308                    // but (for correct assignment / initialization analysis) data flow info must be preserved
309                    assert result.getType() == null || KotlinBuiltIns.isUnit(result.getType());
310                    result = result.replaceType(expressionTypingComponents.builtIns.getUnitType());
311                }
312            }
313            return result;
314        }
315    
316    }