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