/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve;
import org.jetbrains.annotations.
NotNull;
import org.jetbrains.annotations.
Nullable;
import org.jetbrains.kotlin.types.*;
/**
* Bare types are somewhat like raw types, but in Kotlin they are only allowed on the right-hand side of is/as.
* For example:
*
* fun foo(a: Any) {
* if (a is List) {
* // a is known to be List<*> here
* }
* }
*
* Another example:
*
* fun foo(a: Collection<String>) {
* if (a is List) {
* // a is known to be List<String> here
* }
* }
*
* One can call reconstruct(supertype) to get an actual type from a bare type
*/
public class
PossiblyBareType {
@
NotNull
public static
PossiblyBareType bare(@
NotNull TypeConstructor bareTypeConstructor, boolean
nullable) {
return new
PossiblyBareType(null,
bareTypeConstructor,
nullable);
}
@
NotNull
public static
PossiblyBareType type(@
NotNull KotlinType actualType) {
return new
PossiblyBareType(
actualType, null, false);
}
private final
KotlinType actualType;
private final
TypeConstructor bareTypeConstructor;
private final boolean
nullable;
private
PossiblyBareType(@
Nullable KotlinType actualType, @
Nullable TypeConstructor bareTypeConstructor, boolean
nullable) {
this.
actualType =
actualType;
this.
bareTypeConstructor =
bareTypeConstructor;
this.
nullable =
nullable;
}
public boolean
isBare() {
return
actualType == null;
}
@
NotNull
public
KotlinType getActualType() {
//noinspection ConstantConditions
return
actualType;
}
@
NotNull
public
TypeConstructor getBareTypeConstructor() {
//noinspection ConstantConditions
return
bareTypeConstructor;
}
private boolean
isBareTypeNullable() {
return
nullable;
}
public boolean
isNullable() {
if (
isBare()) return
isBareTypeNullable();
return
getActualType().
isMarkedNullable();
}
public
PossiblyBareType makeNullable() {
if (
isBare()) {
return
isBareTypeNullable() ? this :
bare(
getBareTypeConstructor(), true);
}
return
type(
TypeUtils.
makeNullable(
getActualType()));
}
@
NotNull
public
TypeReconstructionResult reconstruct(@
NotNull KotlinType subjectType) {
if (!
isBare()) return new
TypeReconstructionResult(
getActualType(), true);
TypeReconstructionResult reconstructionResult =
CastDiagnosticsUtil.
findStaticallyKnownSubtype(
TypeUtils.
makeNotNullable(
subjectType),
getBareTypeConstructor()
);
KotlinType type =
reconstructionResult.
getResultingType();
// No need to make an absent type nullable
if (
type == null) return
reconstructionResult;
KotlinType resultingType =
TypeUtils.
makeNullableAsSpecified(
type,
isBareTypeNullable());
return new
TypeReconstructionResult(
resultingType,
reconstructionResult.
isAllArgumentsInferred());
}
@
Override
public
String toString() {
return
isBare() ? "bare " +
bareTypeConstructor + (
isBareTypeNullable() ? "?" : "") :
getActualType().
toString();
}
}