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