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 org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
024 import org.jetbrains.kotlin.cfg.WhenChecker;
025 import org.jetbrains.kotlin.descriptors.ClassDescriptor;
026 import org.jetbrains.kotlin.diagnostics.Errors;
027 import org.jetbrains.kotlin.psi.*;
028 import org.jetbrains.kotlin.resolve.BindingContext;
029 import org.jetbrains.kotlin.resolve.DescriptorUtils;
030 import org.jetbrains.kotlin.resolve.PossiblyBareType;
031 import org.jetbrains.kotlin.resolve.TypeResolutionContext;
032 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
033 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
034 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
035 import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
036 import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
037 import org.jetbrains.kotlin.types.*;
038 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
039 import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
040
041 import java.util.Collections;
042 import java.util.Set;
043
044 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean;
045 import static org.jetbrains.kotlin.diagnostics.Errors.*;
046 import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
047 import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
048 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.newWritableScopeImpl;
049
050 public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
051 protected PatternMatchingTypingVisitor(@NotNull ExpressionTypingInternals facade) {
052 super(facade);
053 }
054
055 @Override
056 public KotlinTypeInfo visitIsExpression(@NotNull KtIsExpression expression, ExpressionTypingContext contextWithExpectedType) {
057 ExpressionTypingContext context = contextWithExpectedType
058 .replaceExpectedType(NO_EXPECTED_TYPE)
059 .replaceContextDependency(INDEPENDENT);
060 KtExpression leftHandSide = expression.getLeftHandSide();
061 KotlinTypeInfo typeInfo = facade.safeGetTypeInfo(leftHandSide, context.replaceScope(context.scope));
062 KotlinType knownType = typeInfo.getType();
063 if (expression.getTypeReference() != null) {
064 DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(leftHandSide, knownType, context);
065 DataFlowInfo conditionInfo = checkTypeForIs(context, knownType, expression.getTypeReference(), dataFlowValue).thenInfo;
066 DataFlowInfo newDataFlowInfo = conditionInfo.and(typeInfo.getDataFlowInfo());
067 context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo);
068 }
069 return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(components.builtIns.getBooleanType()), expression, contextWithExpectedType);
070 }
071
072 @Override
073 public KotlinTypeInfo visitWhenExpression(@NotNull KtWhenExpression expression, ExpressionTypingContext context) {
074 return visitWhenExpression(expression, context, false);
075 }
076
077 public KotlinTypeInfo visitWhenExpression(KtWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
078 components.dataFlowAnalyzer.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType);
079
080 ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
081 // TODO :change scope according to the bound value in the when header
082 KtExpression subjectExpression = expression.getSubjectExpression();
083
084 KotlinType subjectType;
085 boolean loopBreakContinuePossible = false;
086 if (subjectExpression == null) {
087 subjectType = ErrorUtils.createErrorType("Unknown type");
088 }
089 else {
090 KotlinTypeInfo typeInfo = facade.safeGetTypeInfo(subjectExpression, context);
091 loopBreakContinuePossible = typeInfo.getJumpOutPossible();
092 subjectType = typeInfo.getType();
093 assert subjectType != null;
094 if (TypeUtils.isNullableType(subjectType) && !WhenChecker.containsNullCase(expression, context.trace)) {
095 ExpressionTypingContext subjectContext = context.replaceExpectedType(TypeUtils.makeNotNullable(subjectType));
096 components.dataFlowAnalyzer.checkPossibleCast(subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext);
097 }
098 context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo());
099 }
100 DataFlowValue subjectDataFlowValue = subjectExpression != null
101 ? DataFlowValueFactory.createDataFlowValue(subjectExpression, subjectType, context)
102 : DataFlowValue.nullValue(components.builtIns);
103
104 // TODO : exhaustive patterns
105
106 Set<KotlinType> expressionTypes = Sets.newHashSet();
107 DataFlowInfo commonDataFlowInfo = null;
108 DataFlowInfo elseDataFlowInfo = context.dataFlowInfo;
109 for (KtWhenEntry whenEntry : expression.getEntries()) {
110 DataFlowInfos infosForCondition = getDataFlowInfosForEntryCondition(
111 whenEntry, context.replaceDataFlowInfo(elseDataFlowInfo), subjectExpression, subjectType, subjectDataFlowValue);
112 elseDataFlowInfo = elseDataFlowInfo.and(infosForCondition.elseInfo);
113
114 KtExpression bodyExpression = whenEntry.getExpression();
115 if (bodyExpression != null) {
116 LexicalWritableScope scopeToExtend = newWritableScopeImpl(context, "Scope extended in when entry");
117 ExpressionTypingContext newContext = contextWithExpectedType
118 .replaceScope(scopeToExtend).replaceDataFlowInfo(infosForCondition.thenInfo).replaceContextDependency(INDEPENDENT);
119 CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION;
120 KotlinTypeInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
121 scopeToExtend, Collections.singletonList(bodyExpression), coercionStrategy, newContext);
122 loopBreakContinuePossible |= typeInfo.getJumpOutPossible();
123 KotlinType type = typeInfo.getType();
124 if (type != null) {
125 expressionTypes.add(type);
126 }
127 if (commonDataFlowInfo == null) {
128 commonDataFlowInfo = typeInfo.getDataFlowInfo();
129 }
130 else {
131 commonDataFlowInfo = commonDataFlowInfo.or(typeInfo.getDataFlowInfo());
132 }
133 }
134 }
135
136 if (commonDataFlowInfo == null) {
137 commonDataFlowInfo = context.dataFlowInfo;
138 }
139 else if (expression.getElseExpression() == null && !WhenChecker.isWhenExhaustive(expression, context.trace)) {
140 // Without else expression in non-exhaustive when, we *must* take initial data flow info into account,
141 // because data flow can bypass all when branches in this case
142 commonDataFlowInfo = commonDataFlowInfo.or(context.dataFlowInfo);
143 }
144
145 return TypeInfoFactoryKt.createTypeInfo(expressionTypes.isEmpty() ? null : components.dataFlowAnalyzer.checkType(
146 components.dataFlowAnalyzer.checkImplicitCast(
147 CommonSupertypes.commonSupertype(expressionTypes), expression,
148 contextWithExpectedType, isStatement),
149 expression, contextWithExpectedType),
150 commonDataFlowInfo,
151 loopBreakContinuePossible,
152 contextWithExpectedType.dataFlowInfo);
153 }
154
155 @NotNull
156 private DataFlowInfos getDataFlowInfosForEntryCondition(
157 @NotNull KtWhenEntry whenEntry,
158 @NotNull ExpressionTypingContext context,
159 @Nullable KtExpression subjectExpression,
160 @NotNull KotlinType subjectType,
161 @NotNull DataFlowValue subjectDataFlowValue
162 ) {
163 if (whenEntry.isElse()) {
164 return new DataFlowInfos(context.dataFlowInfo);
165 }
166
167 DataFlowInfos infos = null;
168 ExpressionTypingContext contextForCondition = context;
169 for (KtWhenCondition condition : whenEntry.getConditions()) {
170 DataFlowInfos conditionInfos = checkWhenCondition(subjectExpression, subjectType, condition,
171 contextForCondition, subjectDataFlowValue);
172 if (infos != null) {
173 infos = new DataFlowInfos(infos.thenInfo.or(conditionInfos.thenInfo), infos.elseInfo.and(conditionInfos.elseInfo));
174 }
175 else {
176 infos = conditionInfos;
177 }
178 contextForCondition = contextForCondition.replaceDataFlowInfo(conditionInfos.elseInfo);
179 }
180 return infos != null ? infos : new DataFlowInfos(context.dataFlowInfo);
181 }
182
183 private DataFlowInfos checkWhenCondition(
184 @Nullable final KtExpression subjectExpression,
185 final KotlinType subjectType,
186 KtWhenCondition condition,
187 final ExpressionTypingContext context,
188 final DataFlowValue subjectDataFlowValue
189 ) {
190 final Ref<DataFlowInfos> newDataFlowInfo = new Ref<DataFlowInfos>(noChange(context));
191 condition.accept(new KtVisitorVoid() {
192 @Override
193 public void visitWhenConditionInRange(@NotNull KtWhenConditionInRange condition) {
194 KtExpression rangeExpression = condition.getRangeExpression();
195 if (rangeExpression == null) return;
196 if (subjectExpression == null) {
197 context.trace.report(EXPECTED_CONDITION.on(condition));
198 DataFlowInfo dataFlowInfo = facade.getTypeInfo(rangeExpression, context).getDataFlowInfo();
199 newDataFlowInfo.set(new DataFlowInfos(dataFlowInfo, dataFlowInfo));
200 return;
201 }
202 ValueArgument argumentForSubject = CallMaker.makeExternalValueArgument(subjectExpression);
203 KotlinTypeInfo typeInfo = facade.checkInExpression(condition, condition.getOperationReference(),
204 argumentForSubject, rangeExpression, context);
205 DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
206 newDataFlowInfo.set(new DataFlowInfos(dataFlowInfo, dataFlowInfo));
207 KotlinType type = typeInfo.getType();
208 if (type == null || !isBoolean(type)) {
209 context.trace.report(TYPE_MISMATCH_IN_RANGE.on(condition));
210 }
211 }
212
213 @Override
214 public void visitWhenConditionIsPattern(@NotNull KtWhenConditionIsPattern condition) {
215 if (subjectExpression == null) {
216 context.trace.report(EXPECTED_CONDITION.on(condition));
217 }
218 if (condition.getTypeReference() != null) {
219 DataFlowInfos result = checkTypeForIs(context, subjectType, condition.getTypeReference(), subjectDataFlowValue);
220 if (condition.isNegated()) {
221 newDataFlowInfo.set(new DataFlowInfos(result.elseInfo, result.thenInfo));
222 }
223 else {
224 newDataFlowInfo.set(result);
225 }
226 }
227 }
228
229 @Override
230 public void visitWhenConditionWithExpression(@NotNull KtWhenConditionWithExpression condition) {
231 KtExpression expression = condition.getExpression();
232 if (expression != null) {
233 newDataFlowInfo.set(checkTypeForExpressionCondition(context, expression, subjectType, subjectExpression == null,
234 subjectDataFlowValue));
235 }
236 }
237
238 @Override
239 public void visitKtElement(@NotNull KtElement element) {
240 context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
241 }
242 });
243 return newDataFlowInfo.get();
244 }
245
246 private static class DataFlowInfos {
247 private final DataFlowInfo thenInfo;
248 private final DataFlowInfo elseInfo;
249
250 private DataFlowInfos(DataFlowInfo thenInfo, DataFlowInfo elseInfo) {
251 this.thenInfo = thenInfo;
252 this.elseInfo = elseInfo;
253 }
254
255 private DataFlowInfos(DataFlowInfo info) {
256 this(info, info);
257 }
258 }
259
260 private DataFlowInfos checkTypeForExpressionCondition(
261 ExpressionTypingContext context,
262 KtExpression expression,
263 KotlinType subjectType,
264 boolean conditionExpected,
265 DataFlowValue subjectDataFlowValue
266 ) {
267 if (expression == null) {
268 return noChange(context);
269 }
270 KotlinTypeInfo typeInfo = facade.getTypeInfo(expression, context);
271 KotlinType type = typeInfo.getType();
272 if (type == null) {
273 return noChange(context);
274 }
275 context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo());
276 if (conditionExpected) {
277 KotlinType booleanType = components.builtIns.getBooleanType();
278 if (!KotlinTypeChecker.DEFAULT.equalTypes(booleanType, type)) {
279 context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(expression, type));
280 }
281 else {
282 DataFlowInfo ifInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(expression, true, context);
283 DataFlowInfo elseInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(expression, false, context);
284 return new DataFlowInfos(ifInfo, elseInfo);
285 }
286 return noChange(context);
287 }
288 checkTypeCompatibility(context, type, subjectType, expression);
289 DataFlowValue expressionDataFlowValue =
290 DataFlowValueFactory.createDataFlowValue(expression, type, context);
291 DataFlowInfos result = noChange(context);
292 result = new DataFlowInfos(
293 result.thenInfo.equate(subjectDataFlowValue, expressionDataFlowValue),
294 result.elseInfo.disequate(subjectDataFlowValue, expressionDataFlowValue)
295 );
296 return result;
297 }
298
299 private DataFlowInfos checkTypeForIs(
300 ExpressionTypingContext context,
301 KotlinType subjectType,
302 KtTypeReference typeReferenceAfterIs,
303 DataFlowValue subjectDataFlowValue
304 ) {
305 if (typeReferenceAfterIs == null) {
306 return noChange(context);
307 }
308 TypeResolutionContext typeResolutionContext = new TypeResolutionContext(context.scope, context.trace, true, /*allowBareTypes=*/ true);
309 PossiblyBareType possiblyBareTarget = components.typeResolver.resolvePossiblyBareType(typeResolutionContext, typeReferenceAfterIs);
310 KotlinType targetType = TypeReconstructionUtil.reconstructBareType(typeReferenceAfterIs, possiblyBareTarget, subjectType, context.trace, components.builtIns);
311
312 if (DynamicTypesKt.isDynamic(targetType)) {
313 context.trace.report(DYNAMIC_NOT_ALLOWED.on(typeReferenceAfterIs));
314 }
315 ClassDescriptor targetDescriptor = TypeUtils.getClassDescriptor(targetType);
316 if (targetDescriptor != null && DescriptorUtils.isEnumEntry(targetDescriptor)) {
317 context.trace.report(IS_ENUM_ENTRY.on(typeReferenceAfterIs));
318 }
319
320 if (!subjectType.isMarkedNullable() && targetType.isMarkedNullable()) {
321 KtTypeElement element = typeReferenceAfterIs.getTypeElement();
322 assert element instanceof KtNullableType : "element must be instance of " + KtNullableType.class.getName();
323 KtNullableType nullableType = (KtNullableType) element;
324 context.trace.report(Errors.USELESS_NULLABLE_CHECK.on(nullableType));
325 }
326 checkTypeCompatibility(context, targetType, subjectType, typeReferenceAfterIs);
327 if (CastDiagnosticsUtil.isCastErased(subjectType, targetType, KotlinTypeChecker.DEFAULT)) {
328 context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(typeReferenceAfterIs, targetType));
329 }
330 return new DataFlowInfos(context.dataFlowInfo.establishSubtyping(subjectDataFlowValue, targetType), context.dataFlowInfo);
331 }
332
333 private static DataFlowInfos noChange(ExpressionTypingContext context) {
334 return new DataFlowInfos(context.dataFlowInfo, context.dataFlowInfo);
335 }
336
337 /*
338 * (a: SubjectType) is Type
339 */
340 private void checkTypeCompatibility(
341 @NotNull ExpressionTypingContext context,
342 @Nullable KotlinType type,
343 @NotNull KotlinType subjectType,
344 @NotNull KtElement reportErrorOn
345 ) {
346 // TODO : Take smart casts into account?
347 if (type == null) {
348 return;
349 }
350 if (TypeIntersector.isIntersectionEmpty(type, subjectType)) {
351 context.trace.report(INCOMPATIBLE_TYPES.on(reportErrorOn, type, subjectType));
352 return;
353 }
354
355 // check if the pattern is essentially a 'null' expression
356 if (KotlinBuiltIns.isNullableNothing(type) && !TypeUtils.isNullableType(subjectType)) {
357 context.trace.report(SENSELESS_NULL_IN_WHEN.on(reportErrorOn));
358 }
359 }
360 }