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 }