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