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