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    }