001    /*
002     * Copyright 2010-2013 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.jet.lang.resolve.calls.autocasts;
018    
019    import org.jetbrains.annotations.NotNull;
020    
021    public enum Nullability {
022        NULL(true, false),
023        NOT_NULL(false, true),
024        UNKNOWN(true, true),
025        IMPOSSIBLE(false, false);
026    
027        @NotNull
028        public static Nullability fromFlags(boolean canBeNull, boolean canBeNonNull) {
029            if (!canBeNull && !canBeNonNull) return IMPOSSIBLE;
030            if (!canBeNull && canBeNonNull) return NOT_NULL;
031            if (canBeNull  && !canBeNonNull) return NULL;
032            return UNKNOWN;
033        }
034    
035        private final boolean canBeNull;
036        private final boolean canBeNonNull;
037    
038        Nullability(boolean canBeNull, boolean canBeNonNull) {
039            this.canBeNull = canBeNull;
040            this.canBeNonNull = canBeNonNull;
041        }
042    
043        public boolean canBeNull() {
044            return canBeNull;
045        }
046    
047        public boolean canBeNonNull() {
048            return canBeNonNull;
049        }
050    
051        @NotNull
052        public Nullability refine(@NotNull Nullability other) {
053            switch (this) {
054                case UNKNOWN:
055                    return other;
056                case IMPOSSIBLE:
057                    return other;
058                case NULL:
059                    switch (other) {
060                        case NOT_NULL: return NOT_NULL;
061                        default: return NULL;
062                    }
063                case NOT_NULL:
064                    switch (other) {
065                        case NULL: return NOT_NULL;
066                        default: return NOT_NULL;
067                    }
068            }
069            throw new IllegalStateException();
070        }
071    
072        @NotNull
073        public Nullability invert() {
074            switch (this) {
075                case NULL:
076                    return NOT_NULL;
077                case NOT_NULL:
078                    return UNKNOWN;
079                case UNKNOWN:
080                    return UNKNOWN;
081                case IMPOSSIBLE:
082                    return UNKNOWN;
083            }
084            throw new IllegalStateException();
085        }
086    
087        @NotNull
088        public Nullability and(@NotNull Nullability other) {
089            return fromFlags(this.canBeNull && other.canBeNull, this.canBeNonNull && other.canBeNonNull);
090        }
091    
092        @NotNull
093        public Nullability or(@NotNull Nullability other) {
094            return fromFlags(this.canBeNull || other.canBeNull, this.canBeNonNull || other.canBeNonNull);
095        }
096    }