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