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
017package org.jetbrains.jet.lang.resolve.calls.autocasts;
018
019import org.jetbrains.annotations.NotNull;
020
021public 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}