001    /*
002     * Copyright 2010-2013 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.jet.lang.types.expressions;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
022    import org.jetbrains.jet.lang.psi.*;
023    import org.jetbrains.jet.lang.resolve.BindingContext;
024    import org.jetbrains.jet.lang.resolve.BindingContextUtils;
025    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
026    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
027    import org.jetbrains.jet.lang.types.DeferredType;
028    import org.jetbrains.jet.lang.types.ErrorUtils;
029    import org.jetbrains.jet.lang.types.JetTypeInfo;
030    import org.jetbrains.jet.util.lazy.ReenteringLazyValueComputationException;
031    
032    import static org.jetbrains.jet.lang.diagnostics.Errors.TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM;
033    
034    public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, ExpressionTypingContext> implements ExpressionTypingInternals {
035    
036        @Override
037        public JetTypeInfo visitIdeTemplate(JetIdeTemplate expression, ExpressionTypingContext data) {
038            return basic.visitIdeTemplate(expression, data);
039        }
040    
041        @NotNull
042        public static ExpressionTypingFacade create(@NotNull PlatformToKotlinClassMap platformToKotlinClassMap) {
043            return new ExpressionTypingVisitorDispatcher(platformToKotlinClassMap, null);
044        }
045    
046        @NotNull
047        public static ExpressionTypingInternals createForBlock(
048                @NotNull PlatformToKotlinClassMap platformToKotlinClassMap,
049                @NotNull WritableScope writableScope
050        ) {
051            return new ExpressionTypingVisitorDispatcher(platformToKotlinClassMap, writableScope);
052        }
053    
054        private final BasicExpressionTypingVisitor basic;
055        private final ExpressionTypingVisitorForStatements statements;
056        private final ClosureExpressionsTypingVisitor closures = new ClosureExpressionsTypingVisitor(this);
057        private final ControlStructureTypingVisitor controlStructures = new ControlStructureTypingVisitor(this);
058        private final PatternMatchingTypingVisitor patterns = new PatternMatchingTypingVisitor(this);
059    
060        private ExpressionTypingVisitorDispatcher(PlatformToKotlinClassMap platformToKotlinClassMap, WritableScope writableScope) {
061            this.basic = new BasicExpressionTypingVisitor(this, platformToKotlinClassMap);
062            if (writableScope != null) {
063                this.statements = new ExpressionTypingVisitorForStatements(this, writableScope, basic, controlStructures, patterns);
064            }
065            else {
066                this.statements = null;
067            }
068        }
069    
070        @NotNull
071        @Override
072        public JetTypeInfo checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @Nullable JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context) {
073            return basic.checkInExpression(callElement, operationSign, left, right, context);
074        }
075    
076        @Override
077        @NotNull
078        public final JetTypeInfo safeGetTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context) {
079            JetTypeInfo typeInfo = getTypeInfo(expression, context);
080            if (typeInfo.getType() != null) {
081                return typeInfo;
082            }
083            return JetTypeInfo.create(ErrorUtils.createErrorType("Type for " + expression.getText()), context.dataFlowInfo);
084        }
085    
086        @Override
087        @NotNull
088        public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context) {
089            return getTypeInfo(expression, context, this);
090        }
091    
092        @Override
093        @NotNull
094        public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement) {
095            if (!isStatement) return getTypeInfo(expression, context);
096            if (statements != null) {
097                return getTypeInfo(expression, context, statements);
098            }
099            return getTypeInfo(expression, context, createStatementVisitor(context));
100        }
101        
102        private ExpressionTypingVisitorForStatements createStatementVisitor(ExpressionTypingContext context) {
103            return new ExpressionTypingVisitorForStatements(this, ExpressionTypingUtils.newWritableScopeImpl(context, "statement scope"), basic, controlStructures, patterns);
104        }
105    
106        @Override
107        public void checkStatementType(@NotNull JetExpression expression, ExpressionTypingContext context) {
108            expression.accept(createStatementVisitor(context), context);
109        }
110    
111        @NotNull
112        private JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
113            JetTypeInfo recordedTypeInfo = BindingContextUtils.getRecordedTypeInfo(expression, context.trace.getBindingContext());
114            if (recordedTypeInfo != null) {
115                return recordedTypeInfo;
116            }
117            JetTypeInfo result;
118            try {
119                result = expression.accept(visitor, context);
120                // Some recursive definitions (object expressions) must put their types in the cache manually:
121                if (context.trace.get(BindingContext.PROCESSED, expression)) {
122                    return JetTypeInfo.create(context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression),
123                                              result.getDataFlowInfo());
124                }
125    
126                if (result.getType() instanceof DeferredType) {
127                    result = JetTypeInfo.create(((DeferredType) result.getType()).getActualType(), result.getDataFlowInfo());
128                }
129                if (result.getType() != null) {
130                    context.trace.record(BindingContext.EXPRESSION_TYPE, expression, result.getType());
131                }
132    
133            }
134            catch (ReenteringLazyValueComputationException e) {
135                context.trace.report(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM.on(expression));
136                result = JetTypeInfo.create(null, context.dataFlowInfo);
137            }
138    
139            if (!context.trace.get(BindingContext.PROCESSED, expression) && !BindingContextUtils.isExpressionWithValidReference(expression, context.trace.getBindingContext())) {
140                context.trace.record(BindingContext.RESOLUTION_SCOPE, expression, context.scope);
141            }
142            context.trace.record(BindingContext.PROCESSED, expression);
143            if (result.getDataFlowInfo() != DataFlowInfo.EMPTY) {
144                context.trace.record(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression, result.getDataFlowInfo());
145            }
146            return result;
147        }  
148    
149        //////////////////////////////////////////////////////////////////////////////////////////////
150    
151        @Override
152        public JetTypeInfo visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext data) {
153            return expression.accept(closures, data);
154        }
155    
156        @Override
157        public JetTypeInfo visitObjectLiteralExpression(JetObjectLiteralExpression expression, ExpressionTypingContext data) {
158            return expression.accept(closures, data);
159        }
160    
161    //////////////////////////////////////////////////////////////////////////////////////////////
162    
163        @Override
164        public JetTypeInfo visitThrowExpression(JetThrowExpression expression, ExpressionTypingContext data) {
165            return expression.accept(controlStructures, data);
166        }
167    
168        @Override
169        public JetTypeInfo visitReturnExpression(JetReturnExpression expression, ExpressionTypingContext data) {
170            return expression.accept(controlStructures, data);
171        }
172    
173        @Override
174        public JetTypeInfo visitContinueExpression(JetContinueExpression expression, ExpressionTypingContext data) {
175            return expression.accept(controlStructures, data);
176        }
177    
178        @Override
179        public JetTypeInfo visitIfExpression(JetIfExpression expression, ExpressionTypingContext data) {
180            return expression.accept(controlStructures, data);
181        }
182    
183        @Override
184        public JetTypeInfo visitTryExpression(JetTryExpression expression, ExpressionTypingContext data) {
185            return expression.accept(controlStructures, data);
186        }
187    
188        @Override
189        public JetTypeInfo visitForExpression(JetForExpression expression, ExpressionTypingContext data) {
190            return expression.accept(controlStructures, data);
191        }
192    
193        @Override
194        public JetTypeInfo visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext data) {
195            return expression.accept(controlStructures, data);
196        }
197    
198        @Override
199        public JetTypeInfo visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext data) {
200            return expression.accept(controlStructures, data);
201        }
202    
203        @Override
204        public JetTypeInfo visitBreakExpression(JetBreakExpression expression, ExpressionTypingContext data) {
205            return expression.accept(controlStructures, data);
206        }
207    
208    //////////////////////////////////////////////////////////////////////////////////////////////
209    
210        @Override
211        public JetTypeInfo visitIsExpression(JetIsExpression expression, ExpressionTypingContext data) {
212            return expression.accept(patterns, data);
213        }
214    
215        @Override
216        public JetTypeInfo visitWhenExpression(JetWhenExpression expression, ExpressionTypingContext data) {
217            return expression.accept(patterns, data);
218        }
219    
220    //////////////////////////////////////////////////////////////////////////////////////////////
221    
222        @Override
223        public JetTypeInfo visitJetElement(JetElement element, ExpressionTypingContext data) {
224            return element.accept(basic, data);
225        }
226    }