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