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 org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
024    import org.jetbrains.kotlin.diagnostics.Errors;
025    import org.jetbrains.kotlin.psi.*;
026    import org.jetbrains.kotlin.resolve.BindingContext;
027    import org.jetbrains.kotlin.resolve.BindingContextUtils;
028    import org.jetbrains.kotlin.resolve.scopes.WritableScope;
029    import org.jetbrains.kotlin.types.DeferredType;
030    import org.jetbrains.kotlin.types.ErrorUtils;
031    import org.jetbrains.kotlin.types.JetType;
032    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
033    import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException;
034    import org.jetbrains.kotlin.utils.KotlinFrontEndException;
035    
036    import static org.jetbrains.kotlin.diagnostics.Errors.TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM;
037    import static org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage.recordScopeAndDataFlowInfo;
038    
039    public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, ExpressionTypingContext> implements ExpressionTypingInternals {
040    
041        public interface StatementVisitorProvider {
042            ExpressionTypingVisitorForStatements get(@NotNull ExpressionTypingContext context);
043        }
044    
045        public class StatementVisitorProviderForBlock implements StatementVisitorProvider {
046            private final ExpressionTypingVisitorForStatements visitorForBlock;
047    
048    
049            public StatementVisitorProviderForBlock(@NotNull WritableScope scope) {
050                visitorForBlock = new ExpressionTypingVisitorForStatements(
051                        ExpressionTypingVisitorDispatcher.this, scope, basic, controlStructures, patterns, functions
052                );
053            }
054    
055            @Override
056            public ExpressionTypingVisitorForStatements get(@NotNull ExpressionTypingContext context) {
057                return visitorForBlock;
058            }
059        }
060    
061        public class StatementVisitorProviderForDeclarations implements StatementVisitorProvider {
062            @Override
063            public ExpressionTypingVisitorForStatements get(@NotNull ExpressionTypingContext context) {
064                return createStatementVisitor(context);
065            }
066        }
067    
068        private static final Logger LOG = Logger.getInstance(ExpressionTypingVisitor.class);
069    
070        @NotNull
071        public static ExpressionTypingFacade create(@NotNull ExpressionTypingComponents components) {
072            ExpressionTypingVisitorDispatcher typingVisitorDispatcher = new ExpressionTypingVisitorDispatcher(components);
073            typingVisitorDispatcher.setProviderForStatements(typingVisitorDispatcher.new StatementVisitorProviderForDeclarations());
074            return typingVisitorDispatcher;
075        }
076    
077        @NotNull
078        public static ExpressionTypingInternals createForBlock(
079                @NotNull ExpressionTypingComponents components,
080                @NotNull WritableScope writableScope
081        ) {
082            ExpressionTypingVisitorDispatcher typingVisitorDispatcher = new ExpressionTypingVisitorDispatcher(components);
083            typingVisitorDispatcher.setProviderForStatements(typingVisitorDispatcher.new StatementVisitorProviderForBlock(writableScope));
084            return typingVisitorDispatcher;
085    
086        }
087    
088        private final ExpressionTypingComponents components;
089        private final BasicExpressionTypingVisitor basic;
090        private StatementVisitorProvider providerForStatements;
091        private final FunctionsTypingVisitor functions;
092        private final ControlStructureTypingVisitor controlStructures;
093        private final PatternMatchingTypingVisitor patterns;
094    
095        public void setProviderForStatements(StatementVisitorProvider providerForStatements) {
096            this.providerForStatements = providerForStatements;
097        }
098    
099        private ExpressionTypingVisitorDispatcher(
100                @NotNull ExpressionTypingComponents components
101        ) {
102            this.components = components;
103            this.basic = new BasicExpressionTypingVisitor(this);
104            this.controlStructures = new ControlStructureTypingVisitor(this);
105            this.patterns = new PatternMatchingTypingVisitor(this);
106            this.functions = new FunctionsTypingVisitor(this);
107        }
108    
109        @Override
110        @NotNull
111        public ExpressionTypingComponents getComponents() {
112            return components;
113        }
114    
115        @NotNull
116        @Override
117        public JetTypeInfo checkInExpression(
118                @NotNull JetElement callElement,
119                @NotNull JetSimpleNameExpression operationSign,
120                @NotNull ValueArgument leftArgument,
121                @Nullable JetExpression right,
122                @NotNull ExpressionTypingContext context
123        ) {
124            return basic.checkInExpression(callElement, operationSign, leftArgument, right, context);
125        }
126    
127        @Override
128        @NotNull
129        public final JetTypeInfo safeGetTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context) {
130            JetTypeInfo typeInfo = getTypeInfo(expression, context);
131            if (typeInfo.getType() != null) {
132                return typeInfo;
133            }
134            return typeInfo
135                    .replaceType(ErrorUtils.createErrorType("Type for " + expression.getText()))
136                    .replaceDataFlowInfo(context.dataFlowInfo);
137        }
138    
139        @Override
140        @NotNull
141        public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context) {
142            return getTypeInfo(expression, context, this);
143        }
144    
145        @Override
146        @NotNull
147        public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement) {
148            if (!isStatement) return getTypeInfo(expression, context);
149            return getTypeInfo(expression, context, providerForStatements.get(context));
150        }
151        
152        private ExpressionTypingVisitorForStatements createStatementVisitor(ExpressionTypingContext context) {
153            return new ExpressionTypingVisitorForStatements(this,
154                                                            ExpressionTypingUtils.newWritableScopeImpl(context, "statement scope"),
155                                                            basic, controlStructures, patterns, functions);
156        }
157    
158        @Override
159        public void checkStatementType(@NotNull JetExpression expression, ExpressionTypingContext context) {
160            expression.accept(createStatementVisitor(context), context);
161        }
162    
163        @NotNull
164        private static JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
165            try {
166                JetTypeInfo recordedTypeInfo = BindingContextUtils.getRecordedTypeInfo(expression, context.trace.getBindingContext());
167                if (recordedTypeInfo != null) {
168                    return recordedTypeInfo;
169                }
170                JetTypeInfo result;
171                try {
172                    result = expression.accept(visitor, context);
173                    // Some recursive definitions (object expressions) must put their types in the cache manually:
174                    //noinspection ConstantConditions
175                    if (context.trace.get(BindingContext.PROCESSED, expression)) {
176                        JetType type = context.trace.getBindingContext().getType(expression);
177                        return result.replaceType(type);
178                    }
179    
180                    if (result.getType() instanceof DeferredType) {
181                        result = result.replaceType(((DeferredType) result.getType()).getDelegate());
182                    }
183                    context.trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, result);
184                }
185                catch (ReenteringLazyValueComputationException e) {
186                    context.trace.report(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM.on(expression));
187                    result = TypeInfoFactoryPackage.noTypeInfo(context);
188                }
189    
190                context.trace.record(BindingContext.PROCESSED, expression);
191                recordScopeAndDataFlowInfo(context.replaceDataFlowInfo(result.getDataFlowInfo()), expression);
192                return result;
193            }
194            catch (ProcessCanceledException e) {
195                throw e;
196            }
197            catch (KotlinFrontEndException e) {
198                throw e;
199            }
200            catch (Throwable e) {
201                context.trace.report(Errors.EXCEPTION_FROM_ANALYZER.on(expression, e));
202                logOrThrowException(expression, e);
203                return TypeInfoFactoryPackage.createTypeInfo(
204                        ErrorUtils.createErrorType(e.getClass().getSimpleName() + " from analyzer"), 
205                        context
206                );        
207            }
208        }
209    
210        private static void logOrThrowException(@NotNull JetExpression expression, Throwable e) {
211            try {
212                // This trows AssertionError in CLI and reports the error in the IDE
213                LOG.error(
214                        "Exception while analyzing expression at " + DiagnosticUtils.atLocation(expression) + ":\n" + expression.getText() + "\n",
215                        e
216                );
217            }
218            catch (AssertionError errorFromLogger) {
219                // If we ended up here, we are in CLI, and the initial exception needs to be rethrown,
220                // simply throwing AssertionError causes its being wrapped over and over again
221                throw new KotlinFrontEndException(errorFromLogger.getMessage(), e);
222            }
223        }
224    
225        //////////////////////////////////////////////////////////////////////////////////////////////
226    
227        @Override
228        public JetTypeInfo visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression, ExpressionTypingContext data) {
229            return expression.accept(functions, data);
230        }
231    
232        @Override
233        public JetTypeInfo visitNamedFunction(@NotNull JetNamedFunction function, ExpressionTypingContext data) {
234            return function.accept(functions, data);
235        }
236    
237    //////////////////////////////////////////////////////////////////////////////////////////////
238    
239        @Override
240        public JetTypeInfo visitThrowExpression(@NotNull JetThrowExpression expression, ExpressionTypingContext data) {
241            return expression.accept(controlStructures, data);
242        }
243    
244        @Override
245        public JetTypeInfo visitReturnExpression(@NotNull JetReturnExpression expression, ExpressionTypingContext data) {
246            return expression.accept(controlStructures, data);
247        }
248    
249        @Override
250        public JetTypeInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext data) {
251            return expression.accept(controlStructures, data);
252        }
253    
254        @Override
255        public JetTypeInfo visitIfExpression(@NotNull JetIfExpression expression, ExpressionTypingContext data) {
256            return expression.accept(controlStructures, data);
257        }
258    
259        @Override
260        public JetTypeInfo visitTryExpression(@NotNull JetTryExpression expression, ExpressionTypingContext data) {
261            return expression.accept(controlStructures, data);
262        }
263    
264        @Override
265        public JetTypeInfo visitForExpression(@NotNull JetForExpression expression, ExpressionTypingContext data) {
266            return expression.accept(controlStructures, data);
267        }
268    
269        @Override
270        public JetTypeInfo visitWhileExpression(@NotNull JetWhileExpression expression, ExpressionTypingContext data) {
271            return expression.accept(controlStructures, data);
272        }
273    
274        @Override
275        public JetTypeInfo visitDoWhileExpression(@NotNull JetDoWhileExpression expression, ExpressionTypingContext data) {
276            return expression.accept(controlStructures, data);
277        }
278    
279        @Override
280        public JetTypeInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext data) {
281            return expression.accept(controlStructures, data);
282        }
283    
284    //////////////////////////////////////////////////////////////////////////////////////////////
285    
286        @Override
287        public JetTypeInfo visitIsExpression(@NotNull JetIsExpression expression, ExpressionTypingContext data) {
288            return expression.accept(patterns, data);
289        }
290    
291        @Override
292        public JetTypeInfo visitWhenExpression(@NotNull JetWhenExpression expression, ExpressionTypingContext data) {
293            return expression.accept(patterns, data);
294        }
295    
296    //////////////////////////////////////////////////////////////////////////////////////////////
297    
298        @Override
299        public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext data) {
300            return element.accept(basic, data);
301        }
302    }