001 /*
002 * Copyright 2010-2016 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 KotlinType actualType) {
052 return new PossiblyBareType(actualType, null, false);
053 }
054
055 private final KotlinType actualType;
056 private final TypeConstructor bareTypeConstructor;
057 private final boolean nullable;
058
059 private PossiblyBareType(@Nullable KotlinType 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 KotlinType 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
095 return type(TypeUtils.makeNullable(getActualType()));
096 }
097
098 @NotNull
099 public TypeReconstructionResult reconstruct(@NotNull KotlinType subjectType) {
100 if (!isBare()) return new TypeReconstructionResult(getActualType(), true);
101
102 TypeReconstructionResult reconstructionResult = CastDiagnosticsUtil.findStaticallyKnownSubtype(
103 TypeUtils.makeNotNullable(subjectType),
104 getBareTypeConstructor()
105 );
106 KotlinType type = reconstructionResult.getResultingType();
107 // No need to make an absent type nullable
108 if (type == null) return reconstructionResult;
109
110 KotlinType resultingType = TypeUtils.makeNullableAsSpecified(type, isBareTypeNullable());
111 return new TypeReconstructionResult(resultingType, reconstructionResult.isAllArgumentsInferred());
112 }
113
114 @Override
115 public String toString() {
116 return isBare() ? "bare " + bareTypeConstructor + (isBareTypeNullable() ? "?" : "") : getActualType().toString();
117 }
118 }