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