001    /*
002     * Copyright 2010-2016 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.resolve.scopes.TraceBasedLocalRedeclarationChecker;
038    import org.jetbrains.kotlin.types.ErrorUtils;
039    import org.jetbrains.kotlin.types.KotlinType;
040    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
041    
042    import java.util.Iterator;
043    import java.util.List;
044    
045    import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
046    import static org.jetbrains.kotlin.types.TypeUtils.UNIT_EXPECTED_TYPE;
047    import static org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
048    
049    public class ExpressionTypingServices {
050    
051        private final ExpressionTypingFacade expressionTypingFacade;
052        private final ExpressionTypingComponents expressionTypingComponents;
053    
054        @NotNull private final AnnotationChecker annotationChecker;
055        @NotNull private final StatementFilter statementFilter;
056    
057        public ExpressionTypingServices(
058                @NotNull ExpressionTypingComponents components,
059                @NotNull AnnotationChecker annotationChecker,
060                @NotNull StatementFilter statementFilter,
061                @NotNull ExpressionTypingVisitorDispatcher.ForDeclarations facade
062        ) {
063            this.expressionTypingComponents = components;
064            this.annotationChecker = annotationChecker;
065            this.statementFilter = statementFilter;
066            this.expressionTypingFacade = facade;
067        }
068    
069        @NotNull public StatementFilter getStatementFilter() {
070            return statementFilter;
071        }
072    
073        @NotNull
074        public KotlinType safeGetType(
075                @NotNull LexicalScope scope,
076                @NotNull KtExpression expression,
077                @NotNull KotlinType expectedType,
078                @NotNull DataFlowInfo dataFlowInfo,
079                @NotNull BindingTrace trace
080        ) {
081            KotlinType type = getType(scope, expression, expectedType, dataFlowInfo, trace);
082    
083            return type != null ? type : ErrorUtils.createErrorType("Type for " + expression.getText());
084        }
085    
086        @NotNull
087        public KotlinTypeInfo getTypeInfo(
088                @NotNull LexicalScope scope,
089                @NotNull KtExpression expression,
090                @NotNull KotlinType expectedType,
091                @NotNull DataFlowInfo dataFlowInfo,
092                @NotNull BindingTrace trace,
093                boolean isStatement
094        ) {
095            ExpressionTypingContext context = ExpressionTypingContext.newContext(
096                    trace, scope, dataFlowInfo, expectedType
097            );
098            return expressionTypingFacade.getTypeInfo(expression, context, isStatement);
099        }
100    
101        @NotNull
102        public KotlinTypeInfo getTypeInfo(@NotNull KtExpression expression, @NotNull ResolutionContext resolutionContext) {
103            return expressionTypingFacade.getTypeInfo(expression, ExpressionTypingContext.newContext(resolutionContext));
104        }
105    
106        @Nullable
107        public KotlinType getType(
108                @NotNull LexicalScope scope,
109                @NotNull KtExpression expression,
110                @NotNull KotlinType expectedType,
111                @NotNull DataFlowInfo dataFlowInfo,
112                @NotNull BindingTrace trace
113        ) {
114            return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace, false).getType();
115        }
116    
117        /////////////////////////////////////////////////////////
118    
119        public void checkFunctionReturnType(
120                @NotNull LexicalScope functionInnerScope,
121                @NotNull KtDeclarationWithBody function,
122                @NotNull FunctionDescriptor functionDescriptor,
123                @NotNull DataFlowInfo dataFlowInfo,
124                @Nullable KotlinType expectedReturnType,
125                BindingTrace trace
126        ) {
127            if (expectedReturnType == null) {
128                expectedReturnType = functionDescriptor.getReturnType();
129                if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
130                    expectedReturnType = NO_EXPECTED_TYPE;
131                }
132            }
133            checkFunctionReturnType(function, ExpressionTypingContext.newContext(
134                    trace,
135                    functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE
136            ));
137        }
138    
139        /*package*/ void checkFunctionReturnType(KtDeclarationWithBody function, ExpressionTypingContext context) {
140            KtExpression bodyExpression = function.getBodyExpression();
141            if (bodyExpression == null) return;
142    
143            boolean blockBody = function.hasBlockBody();
144            ExpressionTypingContext newContext =
145                    blockBody
146                    ? context.replaceExpectedType(NO_EXPECTED_TYPE)
147                    : context;
148    
149            expressionTypingFacade.getTypeInfo(bodyExpression, newContext, blockBody);
150        }
151    
152        @NotNull
153        public KotlinTypeInfo getBlockReturnedType(KtBlockExpression expression, ExpressionTypingContext context, boolean isStatement) {
154            return getBlockReturnedType(expression, isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION, context);
155        }
156    
157        @NotNull
158        public KotlinTypeInfo getBlockReturnedType(
159                @NotNull KtBlockExpression expression,
160                @NotNull CoercionStrategy coercionStrategyForLastExpression,
161                @NotNull ExpressionTypingContext context
162        ) {
163            List<KtExpression> block = StatementFilterKt.filterStatements(statementFilter, expression);
164    
165            DeclarationDescriptor containingDescriptor = context.scope.getOwnerDescriptor();
166            LexicalWritableScope scope = new LexicalWritableScope(context.scope, containingDescriptor, false, null,
167                                                                  new TraceBasedLocalRedeclarationChecker(context.trace), LexicalScopeKind.CODE_BLOCK);
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.freeze();
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                    if (!(statementExpression instanceof KtNamedFunction) || statementExpression.getName() != null) {
297                        mightBeUnit = true;
298                    }
299                }
300                if (statementExpression instanceof KtBinaryExpression) {
301                    KtBinaryExpression binaryExpression = (KtBinaryExpression) statementExpression;
302                    IElementType operationType = binaryExpression.getOperationToken();
303                    //noinspection SuspiciousMethodCalls
304                    if (operationType == KtTokens.EQ || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
305                        mightBeUnit = true;
306                    }
307                }
308                if (mightBeUnit) {
309                    // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments,
310                    // but (for correct assignment / initialization analysis) data flow info must be preserved
311                    assert result.getType() == null || KotlinBuiltIns.isUnit(result.getType());
312                    result = result.replaceType(expressionTypingComponents.builtIns.getUnitType());
313                }
314            }
315            return result;
316        }
317    
318    }