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