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.openapi.diagnostic.Logger;
020    import com.intellij.openapi.progress.ProcessCanceledException;
021    import kotlin.jvm.functions.Function0;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
025    import org.jetbrains.kotlin.diagnostics.Errors;
026    import org.jetbrains.kotlin.psi.*;
027    import org.jetbrains.kotlin.resolve.AnnotationChecker;
028    import org.jetbrains.kotlin.resolve.BindingContext;
029    import org.jetbrains.kotlin.resolve.BindingContextUtils;
030    import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
031    import org.jetbrains.kotlin.types.DeferredType;
032    import org.jetbrains.kotlin.types.ErrorUtils;
033    import org.jetbrains.kotlin.types.JetType;
034    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
035    import org.jetbrains.kotlin.util.PerformanceCounter;
036    import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException;
037    import org.jetbrains.kotlin.utils.KotlinFrontEndException;
038    
039    import static org.jetbrains.kotlin.diagnostics.Errors.TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM;
040    import static org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage.recordScopeAndDataFlowInfo;
041    
042    public abstract class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, ExpressionTypingContext> implements ExpressionTypingInternals {
043    
044        public static final PerformanceCounter typeInfoPerfCounter = PerformanceCounter.Companion.create("Type info", true);
045    
046        private static final Logger LOG = Logger.getInstance(ExpressionTypingVisitor.class);
047    
048        public static class ForDeclarations extends ExpressionTypingVisitorDispatcher {
049            public ForDeclarations(@NotNull ExpressionTypingComponents components, @NotNull AnnotationChecker annotationChecker) {
050                super(components, annotationChecker);
051            }
052    
053            @Override
054            protected ExpressionTypingVisitorForStatements getStatementVisitor(@NotNull ExpressionTypingContext context) {
055                return createStatementVisitor(context);
056            }
057        }
058    
059        protected abstract ExpressionTypingVisitorForStatements getStatementVisitor(@NotNull ExpressionTypingContext context);
060    
061        public static class ForBlock extends ExpressionTypingVisitorDispatcher {
062    
063            private final ExpressionTypingVisitorForStatements visitorForBlock;
064    
065            public ForBlock(
066                    @NotNull ExpressionTypingComponents components,
067                    @NotNull AnnotationChecker annotationChecker,
068                    @NotNull LexicalWritableScope writableScope
069            ) {
070                super(components, annotationChecker);
071                this.visitorForBlock = new ExpressionTypingVisitorForStatements(
072                        this, writableScope, basic, controlStructures, patterns, functions
073                );
074            }
075    
076            @Override
077            protected ExpressionTypingVisitorForStatements getStatementVisitor(@NotNull ExpressionTypingContext context) {
078                return visitorForBlock;
079            }
080        }
081    
082        private final ExpressionTypingComponents components;
083        @NotNull private final AnnotationChecker annotationChecker;
084        protected final BasicExpressionTypingVisitor basic;
085        protected final FunctionsTypingVisitor functions;
086        protected final ControlStructureTypingVisitor controlStructures;
087        protected final PatternMatchingTypingVisitor patterns;
088    
089        private ExpressionTypingVisitorDispatcher(
090                @NotNull ExpressionTypingComponents components,
091                @NotNull AnnotationChecker annotationChecker
092        ) {
093            this.components = components;
094            this.annotationChecker = annotationChecker;
095            this.basic = new BasicExpressionTypingVisitor(this);
096            this.controlStructures = new ControlStructureTypingVisitor(this);
097            this.patterns = new PatternMatchingTypingVisitor(this);
098            this.functions = new FunctionsTypingVisitor(this);
099        }
100    
101        @Override
102        @NotNull
103        public ExpressionTypingComponents getComponents() {
104            return components;
105        }
106    
107        @NotNull
108        @Override
109        public JetTypeInfo checkInExpression(
110                @NotNull JetElement callElement,
111                @NotNull JetSimpleNameExpression operationSign,
112                @NotNull ValueArgument leftArgument,
113                @Nullable JetExpression right,
114                @NotNull ExpressionTypingContext context
115        ) {
116            return basic.checkInExpression(callElement, operationSign, leftArgument, right, context);
117        }
118    
119        @Override
120        @NotNull
121        public final JetTypeInfo safeGetTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context) {
122            JetTypeInfo typeInfo = getTypeInfo(expression, context);
123            if (typeInfo.getType() != null) {
124                return typeInfo;
125            }
126            return typeInfo
127                    .replaceType(ErrorUtils.createErrorType("Type for " + expression.getText()))
128                    .replaceDataFlowInfo(context.dataFlowInfo);
129        }
130    
131        @Override
132        @NotNull
133        public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context) {
134            JetTypeInfo result = getTypeInfo(expression, context, this);
135            annotationChecker.checkExpression(expression, context.trace);
136            return result;
137        }
138    
139        @Override
140        @NotNull
141        public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement) {
142            if (!isStatement) return getTypeInfo(expression, context);
143            return getTypeInfo(expression, context, getStatementVisitor(context));
144        }
145        
146        protected ExpressionTypingVisitorForStatements createStatementVisitor(ExpressionTypingContext context) {
147            return new ExpressionTypingVisitorForStatements(this,
148                                                            ExpressionTypingUtils.newWritableScopeImpl(context, "statement scope"),
149                                                            basic, controlStructures, patterns, functions);
150        }
151    
152        @Override
153        public void checkStatementType(@NotNull JetExpression expression, ExpressionTypingContext context) {
154            expression.accept(createStatementVisitor(context), context);
155        }
156    
157        @NotNull
158        private static JetTypeInfo getTypeInfo(@NotNull final JetExpression expression, final ExpressionTypingContext context, final JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
159            return typeInfoPerfCounter.time(new Function0<JetTypeInfo>() {
160                @Override
161                public JetTypeInfo invoke() {
162                    try {
163                        JetTypeInfo recordedTypeInfo = BindingContextUtils.getRecordedTypeInfo(expression, context.trace.getBindingContext());
164                        if (recordedTypeInfo != null) {
165                            return recordedTypeInfo;
166                        }
167                        JetTypeInfo result;
168                        try {
169                            result = expression.accept(visitor, context);
170                            // Some recursive definitions (object expressions) must put their types in the cache manually:
171                            //noinspection ConstantConditions
172                            if (context.trace.get(BindingContext.PROCESSED, expression)) {
173                                JetType type = context.trace.getBindingContext().getType(expression);
174                                return result.replaceType(type);
175                            }
176    
177                            if (result.getType() instanceof DeferredType) {
178                                result = result.replaceType(((DeferredType) result.getType()).getDelegate());
179                            }
180                            context.trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, result);
181                        }
182                        catch (ReenteringLazyValueComputationException e) {
183                            context.trace.report(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM.on(expression));
184                            result = TypeInfoFactoryPackage.noTypeInfo(context);
185                        }
186    
187                        context.trace.record(BindingContext.PROCESSED, expression);
188                        recordScopeAndDataFlowInfo(context.replaceDataFlowInfo(result.getDataFlowInfo()), expression);
189                        return result;
190                    }
191                    catch (ProcessCanceledException e) {
192                        throw e;
193                    }
194                    catch (KotlinFrontEndException e) {
195                        throw e;
196                    }
197                    catch (Throwable e) {
198                        context.trace.report(Errors.EXCEPTION_FROM_ANALYZER.on(expression, e));
199                        logOrThrowException(expression, e);
200                        return TypeInfoFactoryPackage.createTypeInfo(
201                                ErrorUtils.createErrorType(e.getClass().getSimpleName() + " from analyzer"),
202                                context
203                        );
204                    }
205                }
206            });
207        }
208    
209        private static void logOrThrowException(@NotNull JetExpression expression, Throwable e) {
210            try {
211                // This trows AssertionError in CLI and reports the error in the IDE
212                LOG.error(
213                        "Exception while analyzing expression at " + DiagnosticUtils.atLocation(expression) + ":\n" + expression.getText() + "\n",
214                        e
215                );
216            }
217            catch (AssertionError errorFromLogger) {
218                // If we ended up here, we are in CLI, and the initial exception needs to be rethrown,
219                // simply throwing AssertionError causes its being wrapped over and over again
220                throw new KotlinFrontEndException(errorFromLogger.getMessage(), e);
221            }
222        }
223    
224        //////////////////////////////////////////////////////////////////////////////////////////////
225    
226        @Override
227        public JetTypeInfo visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression, ExpressionTypingContext data) {
228            return functions.visitFunctionLiteralExpression(expression, data);
229        }
230    
231        @Override
232        public JetTypeInfo visitNamedFunction(@NotNull JetNamedFunction function, ExpressionTypingContext data) {
233            return functions.visitNamedFunction(function, data);
234        }
235    
236    //////////////////////////////////////////////////////////////////////////////////////////////
237    
238        @Override
239        public JetTypeInfo visitThrowExpression(@NotNull JetThrowExpression expression, ExpressionTypingContext data) {
240            return controlStructures.visitThrowExpression(expression, data);
241        }
242    
243        @Override
244        public JetTypeInfo visitReturnExpression(@NotNull JetReturnExpression expression, ExpressionTypingContext data) {
245            return controlStructures.visitReturnExpression(expression, data);
246        }
247    
248        @Override
249        public JetTypeInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext data) {
250            return controlStructures.visitContinueExpression(expression, data);
251        }
252    
253        @Override
254        public JetTypeInfo visitIfExpression(@NotNull JetIfExpression expression, ExpressionTypingContext data) {
255            return controlStructures.visitIfExpression(expression, data);
256        }
257    
258        @Override
259        public JetTypeInfo visitTryExpression(@NotNull JetTryExpression expression, ExpressionTypingContext data) {
260            return controlStructures.visitTryExpression(expression, data);
261        }
262    
263        @Override
264        public JetTypeInfo visitForExpression(@NotNull JetForExpression expression, ExpressionTypingContext data) {
265            return controlStructures.visitForExpression(expression, data);
266        }
267    
268        @Override
269        public JetTypeInfo visitWhileExpression(@NotNull JetWhileExpression expression, ExpressionTypingContext data) {
270            return controlStructures.visitWhileExpression(expression, data);
271        }
272    
273        @Override
274        public JetTypeInfo visitDoWhileExpression(@NotNull JetDoWhileExpression expression, ExpressionTypingContext data) {
275            return controlStructures.visitDoWhileExpression(expression, data);
276        }
277    
278        @Override
279        public JetTypeInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext data) {
280            return controlStructures.visitBreakExpression(expression, data);
281        }
282    
283    //////////////////////////////////////////////////////////////////////////////////////////////
284    
285        @Override
286        public JetTypeInfo visitIsExpression(@NotNull JetIsExpression expression, ExpressionTypingContext data) {
287            return patterns.visitIsExpression(expression, data);
288        }
289    
290        @Override
291        public JetTypeInfo visitWhenExpression(@NotNull JetWhenExpression expression, ExpressionTypingContext data) {
292            return patterns.visitWhenExpression(expression, data);
293        }
294    
295    //////////////////////////////////////////////////////////////////////////////////////////////
296    
297        @Override
298        public JetTypeInfo visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, ExpressionTypingContext data) {
299            return basic.visitSimpleNameExpression(expression, data);
300        }
301    
302        @Override
303        public JetTypeInfo visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, ExpressionTypingContext data) {
304            return basic.visitParenthesizedExpression(expression, data);
305        }
306    
307        @Override
308        public JetTypeInfo visitConstantExpression(@NotNull JetConstantExpression expression, ExpressionTypingContext data) {
309            return basic.visitConstantExpression(expression, data);
310        }
311    
312        @Override
313        public JetTypeInfo visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext data) {
314            return basic.visitBinaryWithTypeRHSExpression(expression, data);
315        }
316    
317        @Override
318        public JetTypeInfo visitThisExpression(@NotNull JetThisExpression expression, ExpressionTypingContext data) {
319            return basic.visitThisExpression(expression, data);
320        }
321    
322        @Override
323        public JetTypeInfo visitSuperExpression(@NotNull JetSuperExpression expression, ExpressionTypingContext data) {
324            return basic.visitSuperExpression(expression, data);
325        }
326    
327        @Override
328        public JetTypeInfo visitBlockExpression(@NotNull JetBlockExpression expression, ExpressionTypingContext data) {
329            return basic.visitBlockExpression(expression, data);
330        }
331    
332        @Override
333        public JetTypeInfo visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, ExpressionTypingContext data) {
334            return basic.visitClassLiteralExpression(expression, data);
335        }
336    
337        @Override
338        public JetTypeInfo visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, ExpressionTypingContext data) {
339            return basic.visitCallableReferenceExpression(expression, data);
340        }
341    
342        @Override
343        public JetTypeInfo visitObjectLiteralExpression(@NotNull JetObjectLiteralExpression expression, ExpressionTypingContext data) {
344            return basic.visitObjectLiteralExpression(expression, data);
345        }
346    
347        @Override
348        public JetTypeInfo visitQualifiedExpression(@NotNull JetQualifiedExpression expression, ExpressionTypingContext data) {
349            return basic.visitQualifiedExpression(expression, data);
350        }
351    
352        @Override
353        public JetTypeInfo visitCallExpression(@NotNull JetCallExpression expression, ExpressionTypingContext data) {
354            return basic.visitCallExpression(expression, data);
355        }
356    
357        @Override
358        public JetTypeInfo visitUnaryExpression(@NotNull JetUnaryExpression expression, ExpressionTypingContext data) {
359            return basic.visitUnaryExpression(expression, data);
360        }
361    
362        @Override
363        public JetTypeInfo visitLabeledExpression(@NotNull JetLabeledExpression expression, ExpressionTypingContext data) {
364            return basic.visitLabeledExpression(expression, data);
365        }
366    
367        @Override
368        public JetTypeInfo visitBinaryExpression(@NotNull JetBinaryExpression expression, ExpressionTypingContext data) {
369            return basic.visitBinaryExpression(expression, data);
370        }
371    
372        @Override
373        public JetTypeInfo visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, ExpressionTypingContext data) {
374            return basic.visitArrayAccessExpression(expression, data);
375        }
376    
377        @Override
378        public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext data) {
379            return basic.visitDeclaration(dcl, data);
380        }
381    
382        @Override
383        public JetTypeInfo visitRootPackageExpression(@NotNull JetRootPackageExpression expression, ExpressionTypingContext data) {
384            return basic.visitRootPackageExpression(expression, data);
385        }
386    
387        @Override
388        public JetTypeInfo visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression, ExpressionTypingContext data) {
389            return basic.visitStringTemplateExpression(expression, data);
390        }
391    
392        @Override
393        public JetTypeInfo visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression, ExpressionTypingContext data) {
394            return basic.visitAnnotatedExpression(expression, data);
395        }
396    
397        @Override
398        public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext data) {
399            return element.accept(basic, data);
400        }
401    }