001    package org.jetbrains.jet.lang.resolve;
002    
003    import org.jetbrains.annotations.NotNull;
004    import org.jetbrains.annotations.Nullable;
005    import org.jetbrains.jet.lang.types.*;
006    
007    /**
008     * Bare types are somewhat like raw types, but in Kotlin they are only allowed on the right-hand side of is/as.
009     * For example:
010     *
011     *   fun foo(a: Any) {
012     *     if (a is List) {
013     *       // a is known to be List<*> here
014     *     }
015     *   }
016     *
017     * Another example:
018     *
019     *   fun foo(a: Collection<String>) {
020     *     if (a is List) {
021     *       // a is known to be List<String> here
022     *     }
023     *   }
024     *
025     * One can call reconstruct(supertype) to get an actual type from a bare type
026     */
027    public class PossiblyBareType {
028    
029        @NotNull
030        public static PossiblyBareType bare(@NotNull TypeConstructor bareTypeConstructor, boolean nullable) {
031            return new PossiblyBareType(null, bareTypeConstructor, nullable);
032        }
033    
034        @NotNull
035        public static PossiblyBareType type(@NotNull JetType actualType) {
036            return new PossiblyBareType(actualType, null, false);
037        }
038    
039        private final JetType actualType;
040        private final TypeConstructor bareTypeConstructor;
041        private final boolean nullable;
042    
043        private PossiblyBareType(@Nullable JetType actualType, @Nullable TypeConstructor bareTypeConstructor, boolean nullable) {
044            this.actualType = actualType;
045            this.bareTypeConstructor = bareTypeConstructor;
046            this.nullable = nullable;
047        }
048    
049        public boolean isBare() {
050            return actualType == null;
051        }
052    
053        @NotNull
054        public JetType getActualType() {
055            //noinspection ConstantConditions
056            return actualType;
057        }
058    
059        @NotNull
060        public TypeConstructor getBareTypeConstructor() {
061            //noinspection ConstantConditions
062            return bareTypeConstructor;
063        }
064    
065        private boolean isBareTypeNullable() {
066            return nullable;
067        }
068    
069        public boolean isNullable() {
070            if (isBare()) return isBareTypeNullable();
071            return getActualType().isNullable();
072        }
073    
074        public PossiblyBareType makeNullable() {
075            if (isBare()) {
076                return isBareTypeNullable() ? this : bare(getBareTypeConstructor(), true);
077            }
078            return type(TypeUtils.makeNullable(getActualType()));
079        }
080    
081        @NotNull
082        public TypeReconstructionResult reconstruct(@NotNull JetType subjectType) {
083            if (!isBare()) return new TypeReconstructionResult(getActualType(), true);
084    
085            TypeReconstructionResult reconstructionResult = CastDiagnosticsUtil.findStaticallyKnownSubtype(
086                    TypeUtils.makeNotNullable(subjectType),
087                    getBareTypeConstructor()
088            );
089            JetType type = reconstructionResult.getResultingType();
090            // No need to make an absent type nullable
091            if (type == null) return reconstructionResult;
092    
093            JetType resultingType = TypeUtils.makeNullableAsSpecified(type, isBareTypeNullable());
094            return new TypeReconstructionResult(resultingType, reconstructionResult.isAllArgumentsInferred());
095        }
096    
097        @Override
098        public String toString() {
099            return isBare() ? "bare " + bareTypeConstructor + (isBareTypeNullable() ? "?" : "") : getActualType().toString();
100        }
101    }