001 /*
002 * Copyright 2010-2015 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.kotlin.types.expressions;
018
019 import com.intellij.openapi.diagnostic.Logger;
020 import com.intellij.openapi.progress.ProcessCanceledException;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
024 import org.jetbrains.kotlin.diagnostics.Errors;
025 import org.jetbrains.kotlin.psi.*;
026 import org.jetbrains.kotlin.resolve.BindingContext;
027 import org.jetbrains.kotlin.resolve.BindingContextUtils;
028 import org.jetbrains.kotlin.resolve.scopes.WritableScope;
029 import org.jetbrains.kotlin.types.DeferredType;
030 import org.jetbrains.kotlin.types.ErrorUtils;
031 import org.jetbrains.kotlin.types.JetType;
032 import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
033 import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException;
034 import org.jetbrains.kotlin.utils.KotlinFrontEndException;
035
036 import static org.jetbrains.kotlin.diagnostics.Errors.TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM;
037 import static org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage.recordScopeAndDataFlowInfo;
038
039 public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, ExpressionTypingContext> implements ExpressionTypingInternals {
040
041 public interface StatementVisitorProvider {
042 ExpressionTypingVisitorForStatements get(@NotNull ExpressionTypingContext context);
043 }
044
045 public class StatementVisitorProviderForBlock implements StatementVisitorProvider {
046 private final ExpressionTypingVisitorForStatements visitorForBlock;
047
048
049 public StatementVisitorProviderForBlock(@NotNull WritableScope scope) {
050 visitorForBlock = new ExpressionTypingVisitorForStatements(
051 ExpressionTypingVisitorDispatcher.this, scope, basic, controlStructures, patterns, functions
052 );
053 }
054
055 @Override
056 public ExpressionTypingVisitorForStatements get(@NotNull ExpressionTypingContext context) {
057 return visitorForBlock;
058 }
059 }
060
061 public class StatementVisitorProviderForDeclarations implements StatementVisitorProvider {
062 @Override
063 public ExpressionTypingVisitorForStatements get(@NotNull ExpressionTypingContext context) {
064 return createStatementVisitor(context);
065 }
066 }
067
068 private static final Logger LOG = Logger.getInstance(ExpressionTypingVisitor.class);
069
070 @NotNull
071 public static ExpressionTypingFacade create(@NotNull ExpressionTypingComponents components) {
072 ExpressionTypingVisitorDispatcher typingVisitorDispatcher = new ExpressionTypingVisitorDispatcher(components);
073 typingVisitorDispatcher.setProviderForStatements(typingVisitorDispatcher.new StatementVisitorProviderForDeclarations());
074 return typingVisitorDispatcher;
075 }
076
077 @NotNull
078 public static ExpressionTypingInternals createForBlock(
079 @NotNull ExpressionTypingComponents components,
080 @NotNull WritableScope writableScope
081 ) {
082 ExpressionTypingVisitorDispatcher typingVisitorDispatcher = new ExpressionTypingVisitorDispatcher(components);
083 typingVisitorDispatcher.setProviderForStatements(typingVisitorDispatcher.new StatementVisitorProviderForBlock(writableScope));
084 return typingVisitorDispatcher;
085
086 }
087
088 private final ExpressionTypingComponents components;
089 private final BasicExpressionTypingVisitor basic;
090 private StatementVisitorProvider providerForStatements;
091 private final FunctionsTypingVisitor functions;
092 private final ControlStructureTypingVisitor controlStructures;
093 private final PatternMatchingTypingVisitor patterns;
094
095 public void setProviderForStatements(StatementVisitorProvider providerForStatements) {
096 this.providerForStatements = providerForStatements;
097 }
098
099 private ExpressionTypingVisitorDispatcher(
100 @NotNull ExpressionTypingComponents components
101 ) {
102 this.components = components;
103 this.basic = new BasicExpressionTypingVisitor(this);
104 this.controlStructures = new ControlStructureTypingVisitor(this);
105 this.patterns = new PatternMatchingTypingVisitor(this);
106 this.functions = new FunctionsTypingVisitor(this);
107 }
108
109 @Override
110 @NotNull
111 public ExpressionTypingComponents getComponents() {
112 return components;
113 }
114
115 @NotNull
116 @Override
117 public JetTypeInfo checkInExpression(
118 @NotNull JetElement callElement,
119 @NotNull JetSimpleNameExpression operationSign,
120 @NotNull ValueArgument leftArgument,
121 @Nullable JetExpression right,
122 @NotNull ExpressionTypingContext context
123 ) {
124 return basic.checkInExpression(callElement, operationSign, leftArgument, right, context);
125 }
126
127 @Override
128 @NotNull
129 public final JetTypeInfo safeGetTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context) {
130 JetTypeInfo typeInfo = getTypeInfo(expression, context);
131 if (typeInfo.getType() != null) {
132 return typeInfo;
133 }
134 return typeInfo
135 .replaceType(ErrorUtils.createErrorType("Type for " + expression.getText()))
136 .replaceDataFlowInfo(context.dataFlowInfo);
137 }
138
139 @Override
140 @NotNull
141 public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context) {
142 return getTypeInfo(expression, context, this);
143 }
144
145 @Override
146 @NotNull
147 public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement) {
148 if (!isStatement) return getTypeInfo(expression, context);
149 return getTypeInfo(expression, context, providerForStatements.get(context));
150 }
151
152 private ExpressionTypingVisitorForStatements createStatementVisitor(ExpressionTypingContext context) {
153 return new ExpressionTypingVisitorForStatements(this,
154 ExpressionTypingUtils.newWritableScopeImpl(context, "statement scope"),
155 basic, controlStructures, patterns, functions);
156 }
157
158 @Override
159 public void checkStatementType(@NotNull JetExpression expression, ExpressionTypingContext context) {
160 expression.accept(createStatementVisitor(context), context);
161 }
162
163 @NotNull
164 private static JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetTypeInfo, ExpressionTypingContext> visitor) {
165 try {
166 JetTypeInfo recordedTypeInfo = BindingContextUtils.getRecordedTypeInfo(expression, context.trace.getBindingContext());
167 if (recordedTypeInfo != null) {
168 return recordedTypeInfo;
169 }
170 JetTypeInfo result;
171 try {
172 result = expression.accept(visitor, context);
173 // Some recursive definitions (object expressions) must put their types in the cache manually:
174 //noinspection ConstantConditions
175 if (context.trace.get(BindingContext.PROCESSED, expression)) {
176 JetType type = context.trace.getBindingContext().getType(expression);
177 return result.replaceType(type);
178 }
179
180 if (result.getType() instanceof DeferredType) {
181 result = result.replaceType(((DeferredType) result.getType()).getDelegate());
182 }
183 context.trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, result);
184 }
185 catch (ReenteringLazyValueComputationException e) {
186 context.trace.report(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM.on(expression));
187 result = TypeInfoFactoryPackage.noTypeInfo(context);
188 }
189
190 context.trace.record(BindingContext.PROCESSED, expression);
191 recordScopeAndDataFlowInfo(context.replaceDataFlowInfo(result.getDataFlowInfo()), expression);
192 return result;
193 }
194 catch (ProcessCanceledException e) {
195 throw e;
196 }
197 catch (KotlinFrontEndException e) {
198 throw e;
199 }
200 catch (Throwable e) {
201 context.trace.report(Errors.EXCEPTION_FROM_ANALYZER.on(expression, e));
202 logOrThrowException(expression, e);
203 return TypeInfoFactoryPackage.createTypeInfo(
204 ErrorUtils.createErrorType(e.getClass().getSimpleName() + " from analyzer"),
205 context
206 );
207 }
208 }
209
210 private static void logOrThrowException(@NotNull JetExpression expression, Throwable e) {
211 try {
212 // This trows AssertionError in CLI and reports the error in the IDE
213 LOG.error(
214 "Exception while analyzing expression at " + DiagnosticUtils.atLocation(expression) + ":\n" + expression.getText() + "\n",
215 e
216 );
217 }
218 catch (AssertionError errorFromLogger) {
219 // If we ended up here, we are in CLI, and the initial exception needs to be rethrown,
220 // simply throwing AssertionError causes its being wrapped over and over again
221 throw new KotlinFrontEndException(errorFromLogger.getMessage(), e);
222 }
223 }
224
225 //////////////////////////////////////////////////////////////////////////////////////////////
226
227 @Override
228 public JetTypeInfo visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression, ExpressionTypingContext data) {
229 return expression.accept(functions, data);
230 }
231
232 @Override
233 public JetTypeInfo visitNamedFunction(@NotNull JetNamedFunction function, ExpressionTypingContext data) {
234 return function.accept(functions, data);
235 }
236
237 //////////////////////////////////////////////////////////////////////////////////////////////
238
239 @Override
240 public JetTypeInfo visitThrowExpression(@NotNull JetThrowExpression expression, ExpressionTypingContext data) {
241 return expression.accept(controlStructures, data);
242 }
243
244 @Override
245 public JetTypeInfo visitReturnExpression(@NotNull JetReturnExpression expression, ExpressionTypingContext data) {
246 return expression.accept(controlStructures, data);
247 }
248
249 @Override
250 public JetTypeInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext data) {
251 return expression.accept(controlStructures, data);
252 }
253
254 @Override
255 public JetTypeInfo visitIfExpression(@NotNull JetIfExpression expression, ExpressionTypingContext data) {
256 return expression.accept(controlStructures, data);
257 }
258
259 @Override
260 public JetTypeInfo visitTryExpression(@NotNull JetTryExpression expression, ExpressionTypingContext data) {
261 return expression.accept(controlStructures, data);
262 }
263
264 @Override
265 public JetTypeInfo visitForExpression(@NotNull JetForExpression expression, ExpressionTypingContext data) {
266 return expression.accept(controlStructures, data);
267 }
268
269 @Override
270 public JetTypeInfo visitWhileExpression(@NotNull JetWhileExpression expression, ExpressionTypingContext data) {
271 return expression.accept(controlStructures, data);
272 }
273
274 @Override
275 public JetTypeInfo visitDoWhileExpression(@NotNull JetDoWhileExpression expression, ExpressionTypingContext data) {
276 return expression.accept(controlStructures, data);
277 }
278
279 @Override
280 public JetTypeInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext data) {
281 return expression.accept(controlStructures, data);
282 }
283
284 //////////////////////////////////////////////////////////////////////////////////////////////
285
286 @Override
287 public JetTypeInfo visitIsExpression(@NotNull JetIsExpression expression, ExpressionTypingContext data) {
288 return expression.accept(patterns, data);
289 }
290
291 @Override
292 public JetTypeInfo visitWhenExpression(@NotNull JetWhenExpression expression, ExpressionTypingContext data) {
293 return expression.accept(patterns, data);
294 }
295
296 //////////////////////////////////////////////////////////////////////////////////////////////
297
298 @Override
299 public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext data) {
300 return element.accept(basic, data);
301 }
302 }