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.google.common.collect.Sets;
020 import com.intellij.openapi.util.Ref;
021 import com.intellij.psi.tree.IElementType;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025 import org.jetbrains.kotlin.lexer.KtTokens;
026 import org.jetbrains.kotlin.psi.*;
027 import org.jetbrains.kotlin.resolve.BindingContext;
028 import org.jetbrains.kotlin.resolve.BindingTrace;
029 import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker;
030 import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
031 import org.jetbrains.kotlin.resolve.calls.smartcasts.*;
032 import org.jetbrains.kotlin.resolve.constants.*;
033 import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
034 import org.jetbrains.kotlin.types.DynamicTypesKt;
035 import org.jetbrains.kotlin.types.KotlinType;
036 import org.jetbrains.kotlin.types.TypeUtils;
037 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
038 import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
039
040 import java.util.Collection;
041
042 import static org.jetbrains.kotlin.diagnostics.Errors.*;
043 import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
044 import static org.jetbrains.kotlin.types.TypeUtils.*;
045
046 public class DataFlowAnalyzer {
047
048 private final Iterable<AdditionalTypeChecker> additionalTypeCheckers;
049 private final ConstantExpressionEvaluator constantExpressionEvaluator;
050 private final KotlinBuiltIns builtIns;
051 private final SmartCastManager smartCastManager;
052 private final ExpressionTypingFacade facade;
053
054 public DataFlowAnalyzer(
055 @NotNull Iterable<AdditionalTypeChecker> additionalTypeCheckers,
056 @NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
057 @NotNull KotlinBuiltIns builtIns,
058 @NotNull SmartCastManager smartCastManager,
059 @NotNull ExpressionTypingFacade facade
060 ) {
061 this.additionalTypeCheckers = additionalTypeCheckers;
062 this.constantExpressionEvaluator = constantExpressionEvaluator;
063 this.builtIns = builtIns;
064 this.smartCastManager = smartCastManager;
065 this.facade = facade;
066 }
067
068 @NotNull
069 public DataFlowInfo extractDataFlowInfoFromCondition(
070 @Nullable KtExpression condition,
071 final boolean conditionValue,
072 final ExpressionTypingContext context
073 ) {
074 if (condition == null) return context.dataFlowInfo;
075 final Ref<DataFlowInfo> result = new Ref<DataFlowInfo>(null);
076 condition.accept(new KtVisitorVoid() {
077 @Override
078 public void visitIsExpression(@NotNull KtIsExpression expression) {
079 if (conditionValue && !expression.isNegated() || !conditionValue && expression.isNegated()) {
080 result.set(context.trace.get(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression));
081 }
082 }
083
084 @Override
085 public void visitBinaryExpression(@NotNull KtBinaryExpression expression) {
086 IElementType operationToken = expression.getOperationToken();
087 if (OperatorConventions.BOOLEAN_OPERATIONS.containsKey(operationToken)) {
088 DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, context);
089 KtExpression expressionRight = expression.getRight();
090 if (expressionRight != null) {
091 boolean and = operationToken == KtTokens.ANDAND;
092 DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(
093 expressionRight, conditionValue,
094 and == conditionValue ? context.replaceDataFlowInfo(dataFlowInfo) : context
095 );
096 if (and == conditionValue) { // this means: and && conditionValue || !and && !conditionValue
097 dataFlowInfo = dataFlowInfo.and(rightInfo);
098 }
099 else {
100 dataFlowInfo = dataFlowInfo.or(rightInfo);
101 }
102 }
103 result.set(dataFlowInfo);
104 }
105 else {
106 DataFlowInfo expressionFlowInfo = facade.getTypeInfo(expression, context).getDataFlowInfo();
107 KtExpression left = expression.getLeft();
108 if (left == null) return;
109 KtExpression right = expression.getRight();
110 if (right == null) return;
111
112 KotlinType lhsType = context.trace.getBindingContext().getType(left);
113 if (lhsType == null) return;
114 KotlinType rhsType = context.trace.getBindingContext().getType(right);
115 if (rhsType == null) return;
116
117 DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, lhsType, context);
118 DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rhsType, context);
119
120 Boolean equals = null;
121 if (operationToken == KtTokens.EQEQ || operationToken == KtTokens.EQEQEQ) {
122 equals = true;
123 }
124 else if (operationToken == KtTokens.EXCLEQ || operationToken == KtTokens.EXCLEQEQEQ) {
125 equals = false;
126 }
127 if (equals != null) {
128 if (equals == conditionValue) { // this means: equals && conditionValue || !equals && !conditionValue
129 result.set(context.dataFlowInfo.equate(leftValue, rightValue).and(expressionFlowInfo));
130 }
131 else {
132 result.set(context.dataFlowInfo.disequate(leftValue, rightValue).and(expressionFlowInfo));
133 }
134 }
135 else {
136 result.set(expressionFlowInfo);
137 }
138 }
139 }
140
141 @Override
142 public void visitUnaryExpression(@NotNull KtUnaryExpression expression) {
143 IElementType operationTokenType = expression.getOperationReference().getReferencedNameElementType();
144 if (operationTokenType == KtTokens.EXCL) {
145 KtExpression baseExpression = expression.getBaseExpression();
146 if (baseExpression != null) {
147 result.set(extractDataFlowInfoFromCondition(baseExpression, !conditionValue, context));
148 }
149 }
150 else {
151 visitExpression(expression);
152 }
153 }
154
155 @Override
156 public void visitExpression(@NotNull KtExpression expression) {
157 // In fact, everything is taken from trace here
158 result.set(facade.getTypeInfo(expression, context).getDataFlowInfo());
159 }
160
161 @Override
162 public void visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression) {
163 KtExpression body = expression.getExpression();
164 if (body != null) {
165 body.accept(this);
166 }
167 }
168 });
169 if (result.get() == null) {
170 return context.dataFlowInfo;
171 }
172 return context.dataFlowInfo.and(result.get());
173 }
174
175 @Nullable
176 public KotlinType checkType(@Nullable KotlinType expressionType, @NotNull KtExpression expression, @NotNull ResolutionContext context) {
177 return checkType(expressionType, expression, context, null);
178 }
179
180 @NotNull
181 public KotlinTypeInfo checkType(@NotNull KotlinTypeInfo typeInfo, @NotNull KtExpression expression, @NotNull ResolutionContext context) {
182 return typeInfo.replaceType(checkType(typeInfo.getType(), expression, context));
183 }
184
185 @NotNull
186 private KotlinType checkTypeInternal(
187 @NotNull KotlinType expressionType,
188 @NotNull KtExpression expression,
189 @NotNull ResolutionContext c,
190 @NotNull Ref<Boolean> hasError
191 ) {
192 if (noExpectedType(c.expectedType) || !c.expectedType.getConstructor().isDenotable() ||
193 KotlinTypeChecker.DEFAULT.isSubtypeOf(expressionType, c.expectedType)) {
194 return expressionType;
195 }
196
197 if (expression instanceof KtConstantExpression) {
198 ConstantValue<?> constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, c.trace, c.expectedType);
199 boolean error = new CompileTimeConstantChecker(c.trace, builtIns, true)
200 .checkConstantExpressionType(constantValue, (KtConstantExpression) expression, c.expectedType);
201 if (hasError != null) hasError.set(error);
202 return expressionType;
203 }
204
205 if (expression instanceof KtWhenExpression) {
206 // No need in additional check because type mismatch is already reported for entries
207 return expressionType;
208 }
209
210 KotlinType possibleType = checkPossibleCast(expressionType, expression, c);
211 if (possibleType != null) return possibleType;
212
213 c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType));
214 if (hasError != null) hasError.set(true);
215 return expressionType;
216 }
217
218 @Nullable
219 public KotlinType checkType(
220 @Nullable KotlinType expressionType,
221 @NotNull KtExpression expressionToCheck,
222 @NotNull ResolutionContext c,
223 @Nullable Ref<Boolean> hasError
224 ) {
225 if (hasError == null) {
226 hasError = Ref.create(false);
227 }
228 else {
229 hasError.set(false);
230 }
231
232 KtExpression expression = KtPsiUtil.safeDeparenthesize(expressionToCheck);
233 recordExpectedType(c.trace, expression, c.expectedType);
234
235 if (expressionType == null) return null;
236
237 KotlinType result = checkTypeInternal(expressionType, expression, c, hasError);
238 if (Boolean.FALSE.equals(hasError.get())) {
239 for (AdditionalTypeChecker checker : additionalTypeCheckers) {
240 checker.checkType(expression, expressionType, result, c);
241 }
242 }
243
244 return result;
245 }
246
247 @Nullable
248 public KotlinType checkPossibleCast(
249 @NotNull KotlinType expressionType,
250 @NotNull KtExpression expression,
251 @NotNull ResolutionContext c
252 ) {
253 DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, c);
254
255 SmartCastResult result = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, false);
256 return result != null ? result.getResultType() : null;
257 }
258
259 public void recordExpectedType(@NotNull BindingTrace trace, @NotNull KtExpression expression, @NotNull KotlinType expectedType) {
260 if (expectedType != NO_EXPECTED_TYPE) {
261 KotlinType normalizeExpectedType = expectedType == UNIT_EXPECTED_TYPE ? builtIns.getUnitType() : expectedType;
262 trace.record(BindingContext.EXPECTED_EXPRESSION_TYPE, expression, normalizeExpectedType);
263 }
264 }
265
266 @Nullable
267 public KotlinType checkStatementType(@NotNull KtExpression expression, @NotNull ResolutionContext context) {
268 if (!noExpectedType(context.expectedType) && !KotlinBuiltIns.isUnit(context.expectedType) && !context.expectedType.isError()) {
269 context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
270 return null;
271 }
272 return builtIns.getUnitType();
273 }
274
275 @Nullable
276 public KotlinType checkImplicitCast(@Nullable KotlinType expressionType, @NotNull KtExpression expression, @NotNull ResolutionContext context, boolean isStatement) {
277 boolean isIfExpression = expression instanceof KtIfExpression;
278 if (expressionType != null && (context.expectedType == NO_EXPECTED_TYPE || isIfExpression)
279 && context.contextDependency == INDEPENDENT && !isStatement
280 && (KotlinBuiltIns.isUnit(expressionType) || KotlinBuiltIns.isAnyOrNullableAny(expressionType))
281 && !DynamicTypesKt.isDynamic(expressionType)) {
282 if (isIfExpression && KotlinBuiltIns.isUnit(expressionType)) {
283 KtIfExpression ifExpression = (KtIfExpression) expression;
284 if (ifExpression.getThen() == null || ifExpression.getElse() == null) {
285 context.trace.report(INVALID_IF_AS_EXPRESSION.on((KtIfExpression) expression));
286 return expressionType;
287 }
288 }
289 else if (isIfExpression && context.expectedType != NO_EXPECTED_TYPE) {
290 return expressionType;
291 }
292 else {
293 context.trace.report(IMPLICIT_CAST_TO_UNIT_OR_ANY.on(expression, expressionType));
294 }
295 }
296 return expressionType;
297 }
298
299 @NotNull
300 public KotlinTypeInfo checkImplicitCast(@NotNull KotlinTypeInfo typeInfo, @NotNull KtExpression expression, @NotNull ResolutionContext context, boolean isStatement) {
301 return typeInfo.replaceType(checkImplicitCast(typeInfo.getType(), expression, context, isStatement));
302 }
303
304 @NotNull
305 public KotlinTypeInfo illegalStatementType(@NotNull KtExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) {
306 facade.checkStatementType(
307 expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
308 context.trace.report(EXPRESSION_EXPECTED.on(expression, expression));
309 return TypeInfoFactoryKt.noTypeInfo(context);
310 }
311
312 @NotNull
313 public Collection<KotlinType> getAllPossibleTypes(
314 @NotNull KtExpression expression,
315 @NotNull DataFlowInfo dataFlowInfo,
316 @NotNull KotlinType type,
317 @NotNull ResolutionContext c
318 ) {
319 DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, c);
320 Collection<KotlinType> possibleTypes = Sets.newHashSet(type);
321 if (dataFlowValue.isPredictable()) {
322 possibleTypes.addAll(dataFlowInfo.getPossibleTypes(dataFlowValue));
323 }
324 return possibleTypes;
325 }
326
327 @NotNull
328 public KotlinTypeInfo createCheckedTypeInfo(
329 @Nullable KotlinType type,
330 @NotNull ResolutionContext<?> context,
331 @NotNull KtExpression expression
332 ) {
333 return checkType(TypeInfoFactoryKt.createTypeInfo(type, context), expression, context);
334 }
335
336 @NotNull
337 public KotlinTypeInfo createCompileTimeConstantTypeInfo(
338 @NotNull CompileTimeConstant<?> value,
339 @NotNull KtExpression expression,
340 @NotNull ExpressionTypingContext context
341 ) {
342 KotlinType expressionType;
343 if (value instanceof IntegerValueTypeConstant) {
344 IntegerValueTypeConstant integerValueTypeConstant = (IntegerValueTypeConstant) value;
345 if (context.contextDependency == INDEPENDENT) {
346 expressionType = integerValueTypeConstant.getType(context.expectedType);
347 constantExpressionEvaluator.updateNumberType(expressionType, expression, context.statementFilter, context.trace);
348 }
349 else {
350 expressionType = integerValueTypeConstant.getUnknownIntegerType();
351 }
352 }
353 else {
354 expressionType = ((TypedCompileTimeConstant<?>) value).getType();
355 }
356
357 return createCheckedTypeInfo(expressionType, context, expression);
358 }
359 }