Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1232: Include type hint into KSErrorType. #1848

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -691,7 +691,8 @@ class ResolverImpl(
builtIns.arrayType.replace(typeArgs)
}
else -> {
getClassDeclarationByName(psiType.canonicalText)?.asStarProjectedType() ?: KSErrorType
getClassDeclarationByName(psiType.canonicalText)?.asStarProjectedType()
?: KSErrorType(psiType.canonicalText)
}
}
}
Expand Down Expand Up @@ -1053,7 +1054,7 @@ class ResolverImpl(
}
}
// if substitution fails, fallback to the type from the property
return KSErrorType
return KSErrorType.fromReferenceBestEffort(property.type)
}

internal fun asMemberOf(
Expand Down Expand Up @@ -1246,7 +1247,7 @@ class ResolverImpl(
}

// Convert type arguments for Java wildcard, recursively.
private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType? {
private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType {
val parameters = constructor.parameters
val arguments = arguments

Expand All @@ -1257,16 +1258,18 @@ class ResolverImpl(
argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT
) {
// conflicting variances
// TODO: error message
return null
throw IllegalArgumentException(
Copy link
Contributor Author

@Jeffset Jeffset Apr 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took liberty in making this an exception. My argument is that returning an error type in a situation seemingly close to an internal error is a bit weird, maybe it's better to crash. If we are not ready to make such decision here, please tell me, and I'll revert to returning null and later on an error type.

"Conflicting variance: variance '${parameter.variance.label}' vs projection " +
"'${argument.projectionKind.label}'"
)
}

val argMode = mode.updateFromAnnotations(argument.type)
val variance = KotlinTypeMapper.getVarianceForWildcard(parameter, argument, argMode)
val genericMode = argMode.toGenericArgumentMode(
getEffectiveVariance(parameter.variance, argument.projectionKind)
)
TypeProjectionImpl(variance, argument.type.toWildcard(genericMode) ?: return null)
TypeProjectionImpl(variance, argument.type.toWildcard(genericMode))
}

return replace(wildcardArguments)
Expand Down Expand Up @@ -1368,19 +1371,17 @@ class ResolverImpl(
if (position == RefPosition.SUPER_TYPE &&
argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT
) {
// Type projection isn't allowed in immediate arguments to supertypes.
// TODO: error message
return KSTypeReferenceSyntheticImpl.getCached(KSErrorType, null)
throw IllegalArgumentException("Type projection isn't allowed in immediate arguments to supertypes")
}
}

val wildcardType = kotlinType.toWildcard(typeMappingMode)?.let {
val wildcardType = kotlinType.toWildcard(typeMappingMode).let {
var candidate: KotlinType = it
for (i in indexes.reversed()) {
candidate = candidate.arguments[i].type
}
getKSTypeCached(candidate)
} ?: KSErrorType
}

return KSTypeReferenceSyntheticImpl.getCached(wildcardType, null)
}
Expand Down
Expand Up @@ -62,7 +62,9 @@ import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.AnnotationResolverImpl
import org.jetbrains.kotlin.resolve.BindingContext
Expand Down Expand Up @@ -161,7 +163,7 @@ private fun <T> ConstantValue<T>.toValue(parent: KSNode): Any? = when (this) {
} else classValue.classId.findKSType()
is KClassValue.Value.LocalClass -> getKSTypeCached(classValue.type)
}
is ErrorValue -> KSErrorType
is ErrorValue -> KSErrorType(toString())
is NullValue -> null
else -> value
}
Expand Down Expand Up @@ -211,7 +213,7 @@ fun LazyAnnotationDescriptor.getValueArguments(): Map<Name, ConstantValue<*>> {
} else if (resolvedArgument is DefaultValueArgument) {
valueParameter.name to DefaultConstantValue
} else {
c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument)?.let { value ->
c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument).let { value ->
val argExp = resolvedArgument.arguments.lastOrNull()?.getArgumentExpression()
// When some elements are not available, the expected and actual size of an array argument will
// be different. In such case, we need to reconstruct the array.
Expand All @@ -224,17 +226,22 @@ fun LazyAnnotationDescriptor.getValueArguments(): Map<Name, ConstantValue<*>> {
val bc = ResolverImpl.instance!!.bindingTrace.bindingContext
val args = argExp.innerExpressions.map {
bc.get(BindingContext.COMPILE_TIME_VALUE, it)?.toConstantValue(value.type)
?: ErrorValue.create("<ERROR VALUE>")
?: it.asErrorValue()
}
valueParameter.name to TypedArrayValue(args, value.type)
} else {
valueParameter.name to value
valueParameter.name to (value ?: argExp?.asErrorValue() ?: ErrorValue.create("ERROR VALUE"))
}
} ?: (valueParameter.name to ErrorValue.create("<ERROR VALUE>"))
}
}
}.toMap()
}

private fun KtExpression.asErrorValue(): ErrorValue {
val reprExpr = (this as? KtClassLiteralExpression)?.receiverExpression ?: this
return ErrorValue.create(reprExpr.text)
}

fun AnnotationDescriptor.createKSValueArguments(ownerAnnotation: KSAnnotation): List<KSValueArgument> {
val allValueArgs = if (this is LazyAnnotationDescriptor) {
this.getValueArguments()
Expand Down Expand Up @@ -419,14 +426,14 @@ fun ValueParameterDescriptor.getDefaultValue(ownerAnnotation: KSAnnotation): Any
if (!this.type.isError) {
defaultValue?.convert(this.type)?.toValue(ownerAnnotation)
} else {
KSErrorType
KSErrorType.fromKtErrorType(type)
}
}
}
is KtParameter -> if (!this.type.isError) {
ResolverImpl.instance!!.evaluateConstant(psi.defaultValue, this.type)?.toValue(ownerAnnotation)
} else {
KSErrorType
KSErrorType.fromKtErrorType(type)
}
is PsiAnnotationMethod -> {
when (psi.defaultValue) {
Expand Down
Expand Up @@ -153,7 +153,7 @@ class KSClassDeclarationDescriptorImpl private constructor(val descriptor: Class
override fun asType(typeArguments: List<KSTypeArgument>): KSType =
descriptor.defaultType.replaceTypeArguments(typeArguments)?.let {
getKSTypeCached(it, typeArguments)
} ?: KSErrorType
} ?: KSErrorType()

override fun asStarProjectedType(): KSType {
return getKSTypeCached(descriptor.defaultType.replaceArgumentsWithStarProjections())
Expand Down
Expand Up @@ -97,7 +97,7 @@ class KSClassDeclarationJavaEnumEntryImpl private constructor(val psi: PsiEnumCo
// Enum can't have type parameters.
override fun asType(typeArguments: List<KSTypeArgument>): KSType {
if (typeArguments.isNotEmpty())
return KSErrorType
return KSErrorType()
return asStarProjectedType()
}

Expand Down
Expand Up @@ -157,13 +157,13 @@ class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) :
it.defaultType.replaceTypeArguments(typeArguments)?.let {
getKSTypeCached(it, typeArguments)
}
} ?: KSErrorType
} ?: KSErrorType()
}

override fun asStarProjectedType(): KSType {
return descriptor?.let {
getKSTypeCached(it.defaultType.replaceArgumentsWithStarProjections())
} ?: KSErrorType
} ?: KSErrorType()
}

override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
Expand Down
Expand Up @@ -124,11 +124,13 @@ class KSTypeReferenceJavaImpl private constructor(val psi: PsiType, override val
.mapNotNull {
(it.annotationType.resolve() as? KSTypeImpl)?.kotlinType?.constructor?.declarationDescriptor?.fqNameSafe
}
val resolved = if ((resolvedType.declaration as? KSClassDeclarationDescriptorImpl)
?.descriptor is NotFoundClasses.MockClassDescriptor
) {
KSErrorType
} else resolvedType
val resolved = when (val declaration = resolvedType.declaration) {
is KSClassDeclarationDescriptorImpl -> when (val descriptor = declaration.descriptor) {
is NotFoundClasses.MockClassDescriptor -> KSErrorType(descriptor.name.asString())
else -> resolvedType
}
else -> resolvedType
}
val hasNotNull = relatedAnnotations.any { it in NOT_NULL_ANNOTATIONS }
val hasNullable = relatedAnnotations.any { it in NULLABLE_ANNOTATIONS }
return if (hasNullable && !hasNotNull) {
Expand Down
Expand Up @@ -47,13 +47,14 @@ class KSTypeReferenceLiteJavaImpl private constructor(val psiElement: PsiElement
val type: KSType by lazy {
when (psiElement) {
is PsiAnnotation -> {
val psiClass = psiElement.nameReferenceElement!!.resolve() as? PsiClass
val nameReferenceElement = psiElement.nameReferenceElement!!
val psiClass = nameReferenceElement.resolve() as? PsiClass
psiClass?.let {
(psiElement.containingFile as? PsiJavaFile)?.let {
ResolverImpl.instance!!.incrementalContext.recordLookup(it, psiClass.qualifiedName!!)
}
KSClassDeclarationJavaImpl.getCached(psiClass).asStarProjectedType()
} ?: KSErrorType
} ?: KSErrorType(nameReferenceElement.text)
}
is PsiMethod -> {
KSClassDeclarationJavaImpl.getCached(psiElement.containingClass!!).asStarProjectedType()
Expand Down
Expand Up @@ -124,7 +124,7 @@ class KSClassDeclarationImpl private constructor(val ktClassOrObject: KtClassOrO
override fun asType(typeArguments: List<KSTypeArgument>): KSType {
return descriptor.defaultType.replaceTypeArguments(typeArguments)?.let {
getKSTypeCached(it, typeArguments)
} ?: KSErrorType
} ?: KSErrorType()
}

override fun asStarProjectedType(): KSType {
Expand Down
Expand Up @@ -19,17 +19,28 @@ package com.google.devtools.ksp.symbol.impl.kotlin

import com.google.devtools.ksp.symbol.*
import com.google.devtools.ksp.symbol.impl.synthetic.KSErrorTypeClassDeclaration
import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.error.ErrorType
import org.jetbrains.kotlin.types.error.ErrorTypeKind

object KSErrorType : KSType {
override val annotations: Sequence<KSAnnotation> = emptySequence()
class KSErrorType(
val nameHint: String? = null,
) : KSType {
override val annotations: Sequence<KSAnnotation>
get() = emptySequence()

override val arguments: List<KSTypeArgument> = emptyList()
override val arguments: List<KSTypeArgument>
get() = emptyList()

override val declaration: KSDeclaration = KSErrorTypeClassDeclaration
override val declaration: KSDeclaration
get() = KSErrorTypeClassDeclaration(this)

override val isError: Boolean = true
override val isError: Boolean
get() = true

override val nullability: Nullability = Nullability.NULLABLE
override val nullability: Nullability
get() = Nullability.NULLABLE

override fun isAssignableFrom(that: KSType): Boolean {
return false
Expand All @@ -51,7 +62,8 @@ object KSErrorType : KSType {
return this
}

override val isMarkedNullable: Boolean = false
override val isMarkedNullable: Boolean
get() = false

override fun replace(arguments: List<KSTypeArgument>): KSType {
return this
Expand All @@ -61,11 +73,51 @@ object KSErrorType : KSType {
return this
}

override fun toString(): String {
return "<ERROR TYPE>"
}
override fun toString(): String = nameHint?.let { "<ERROR TYPE: $it>" } ?: "<ERROR TYPE>"

override val isFunctionType: Boolean
get() = false

override val isSuspendFunctionType: Boolean
get() = false

override val isFunctionType: Boolean = false
override fun hashCode() = nameHint.hashCode()

override val isSuspendFunctionType: Boolean = false
override fun equals(other: Any?): Boolean {
return this === other || other is KSErrorType && other.nameHint == nameHint
}

companion object {
fun fromReferenceBestEffort(reference: KSTypeReference?): KSErrorType {
return when (val type = reference?.resolve()) {
is KSErrorType -> type
null -> KSErrorType(reference?.element?.toString())
else -> KSErrorType(type.toString())
}
}

fun fromKtErrorType(ktType: KotlinType): KSErrorType {
// Logic is in sync with `KotlinType.isError`
val errorType: ErrorType = when (val unwrapped = ktType.unwrap()) {
is ErrorType -> unwrapped
is FlexibleType -> unwrapped.delegate as? ErrorType
else -> null
} ?: throw IllegalArgumentException("Not an error type: $ktType")

val hint = when (errorType.kind) {
// Handle "Unresolved types" group
ErrorTypeKind.UNRESOLVED_TYPE,
ErrorTypeKind.UNRESOLVED_CLASS_TYPE,
ErrorTypeKind.UNRESOLVED_JAVA_CLASS,
ErrorTypeKind.UNRESOLVED_DECLARATION,
ErrorTypeKind.UNRESOLVED_KCLASS_CONSTANT_VALUE,
ErrorTypeKind.UNRESOLVED_TYPE_ALIAS -> errorType.formatParams.first()

// TODO: Handle more ErrorTypeKinds where it's possible to extract a name for the error type.
else -> errorType.debugMessage
}

return KSErrorType(hint)
}
}
}
Expand Up @@ -29,18 +29,19 @@ class KSFunctionErrorImpl(
) : KSFunction {
override val isError: Boolean = true

override val returnType: KSType = KSErrorType
override val returnType: KSType
get() = KSErrorType.fromReferenceBestEffort(declaration.returnType)

override val parameterTypes: List<KSType?>
get() = declaration.parameters.map {
KSErrorType
KSErrorType.fromReferenceBestEffort(it.type)
}
override val typeParameters: List<KSTypeParameter>
get() = emptyList()

override val extensionReceiverType: KSType?
get() = declaration.extensionReceiver?.let {
KSErrorType
KSErrorType.fromReferenceBestEffort(it)
}

override fun equals(other: Any?): Boolean {
Expand Down
Expand Up @@ -97,7 +97,7 @@ class KSPropertyDeclarationImpl private constructor(val ktProperty: KtProperty)
KSTypeReferenceDeferredImpl.getCached(this) {
val desc = propertyDescriptor as? VariableDescriptorWithAccessors
if (desc == null) {
KSErrorType
KSErrorType()
} else {
getKSTypeCached(desc.type)
}
Expand Down
Expand Up @@ -97,7 +97,7 @@ class KSTypeImpl private constructor(
override fun replace(arguments: List<KSTypeArgument>): KSType {
return kotlinType.replaceTypeArguments(arguments)?.let {
getKSTypeCached(it, arguments, annotations)
} ?: KSErrorType
} ?: KSErrorType()
}

override fun starProjection(): KSType {
Expand Down Expand Up @@ -136,10 +136,12 @@ fun getKSTypeCached(
ksTypeArguments: List<KSTypeArgument>? = null,
annotations: Sequence<KSAnnotation> = sequenceOf()
): KSType {
return if (kotlinType.isError ||
kotlinType.constructor.declarationDescriptor is NotFoundClasses.MockClassDescriptor
) {
KSErrorType
if (kotlinType.isError) {
return KSErrorType.fromKtErrorType(kotlinType)
}
val descriptor = kotlinType.constructor.declarationDescriptor
return if (descriptor is NotFoundClasses.MockClassDescriptor) {
KSErrorType(descriptor.name.asString())
} else {
KSTypeImpl.getCached(
kotlinType,
Expand Down
Expand Up @@ -112,7 +112,7 @@ class KSValueParameterImpl private constructor(val ktParameter: KtParameter) : K

override val type: KSTypeReference by lazy {
ktParameter.typeReference?.let { KSTypeReferenceImpl.getCached(it) }
?: findPropertyForAccessor()?.type ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType, this)
?: findPropertyForAccessor()?.type ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType(), this)
}

override val hasDefault: Boolean = ktParameter.hasDefaultValue()
Expand Down