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    }