blob: f50fc71c6b8ccb26e2552d498a5e0755bccf0eed [file] [log] [blame]
/*
* 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.types
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker
/**
* [KotlinType] has only two direct subclasses: [WrappedType] and [UnwrappedType].
*
* WrappedType is used for lazy computations and for other purposes,
* where we cannot compute type directly because of lazy initializations.
* We cannot check type on instanceOf directly, because WrappedType is a wrapper around type.
*
* To solve this problem, there is another subclass of KotlinType -- UnwrappedType.
* So, if you have instance of UnwrappedType, you can safely check this type by instanceOf.
* To get UnwrappedType you should call method [unwrap].
*
* For example, if you want to check, that current type is Flexible, you should run the following:
* `type.unwrap() is FlexibleType`.
* For more examples see usages of method [unwrap].
*
* For type creation see [KotlinTypeFactory].
*/
sealed class KotlinType : Annotated {
abstract val constructor: TypeConstructor
abstract val arguments: List<TypeProjection>
abstract val isMarkedNullable: Boolean
abstract val memberScope: MemberScope
abstract fun unwrap(): UnwrappedType
final override fun hashCode(): Int {
if (isError) return super.hashCode()
var result = constructor.hashCode()
result = 31 * result + arguments.hashCode()
result = 31 * result + if (isMarkedNullable) 1 else 0
return result
}
final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is KotlinType) return false
return isMarkedNullable == other.isMarkedNullable && StrictEqualityTypeChecker.strictEqualTypes(unwrap(), other.unwrap())
}
}
abstract class WrappedType : KotlinType() {
open fun isComputed(): Boolean = true
protected abstract val delegate: KotlinType
override val annotations: Annotations get() = delegate.annotations
override val constructor: TypeConstructor get() = delegate.constructor
override val arguments: List<TypeProjection> get() = delegate.arguments
override val isMarkedNullable: Boolean get() = delegate.isMarkedNullable
override val memberScope: MemberScope get() = delegate.memberScope
override final fun unwrap(): UnwrappedType {
var result = delegate
while (result is WrappedType) {
result = result.delegate
}
return result as UnwrappedType
}
override fun toString(): String {
return if (isComputed()) {
delegate.toString()
}
else {
"<Not computed yet>"
}
}
}
/**
* If you have instance of this type, you can safety check it using instanceOf.
*
* WARNING: For wrappers around types you should use only [WrappedType].
*
* Methods [replaceAnnotations] and [makeNullableAsSpecified] exist here,
* because type should save its own internal structure when we want to replace nullability or annotations.
* For example: nullable captured type still should be captured type.
*
* todo: specify what happens with internal structure when we apply some [TypeSubstitutor]
*/
sealed class UnwrappedType: KotlinType() {
abstract fun replaceAnnotations(newAnnotations: Annotations): UnwrappedType
abstract fun makeNullableAsSpecified(newNullability: Boolean): UnwrappedType
override final fun unwrap(): UnwrappedType = this
}
/**
* This type represents simple type. If you have pure kotlin code without java classes and dynamic types,
* then all your types are simple.
* Or more precisely, all instances are subclasses of [SimpleType] or [WrappedType] (which contains [SimpleType] inside).
*/
abstract class SimpleType : UnwrappedType() {
abstract override fun replaceAnnotations(newAnnotations: Annotations): SimpleType
abstract override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType
override fun toString(): String {
return buildString {
for ((annotation, target) in annotations.getAllAnnotations()) {
append("[", DescriptorRenderer.DEBUG_TEXT.renderAnnotation(annotation, target), "] ")
}
append(constructor)
if (!arguments.isEmpty()) arguments.joinTo(this, separator = ", ", prefix = "<", postfix = ">")
if (isMarkedNullable) append("?")
}
}
}
// lowerBound is a subtype of upperBound
abstract class FlexibleType(val lowerBound: SimpleType, val upperBound: SimpleType) :
UnwrappedType(), SubtypingRepresentatives {
abstract val delegate: SimpleType
override val subTypeRepresentative: KotlinType
get() = lowerBound
override val superTypeRepresentative: KotlinType
get() = upperBound
override fun sameTypeConstructor(type: KotlinType) = false
abstract fun render(renderer: DescriptorRenderer, options: DescriptorRendererOptions): String
override val annotations: Annotations get() = delegate.annotations
override val constructor: TypeConstructor get() = delegate.constructor
override val arguments: List<TypeProjection> get() = delegate.arguments
override val isMarkedNullable: Boolean get() = delegate.isMarkedNullable
override val memberScope: MemberScope get() = delegate.memberScope
override fun toString(): String = DescriptorRenderer.DEBUG_TEXT.renderType(this)
}
val KotlinType.isError: Boolean
get() = unwrap().let { unwrapped ->
unwrapped is ErrorType ||
(unwrapped is FlexibleType && unwrapped.delegate is ErrorType)
}