Skip to content

Commit 1e8486e

Browse files
Jeffsetneetopia
authored andcommitted
#1232: Include type hint into KSErrorType.
This CL makes `KSErrorType` a class with a string "hint", that by convention should be a "simpleName" of an unresolved type. `KSErrorTypeClassDeclaration` is also no longer a singleton and references a corresponding `KSErrorType`. The implementation consists of extracting the available info on the unresolved type on the best effort basis.
1 parent d8efe45 commit 1e8486e

32 files changed

+368
-165
lines changed

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,8 @@ class ResolverImpl(
692692
builtIns.arrayType.replace(typeArgs)
693693
}
694694
else -> {
695-
getClassDeclarationByName(psiType.canonicalText)?.asStarProjectedType() ?: KSErrorType
695+
getClassDeclarationByName(psiType.canonicalText)?.asStarProjectedType()
696+
?: KSErrorType(psiType.canonicalText)
696697
}
697698
}
698699
}
@@ -1054,7 +1055,7 @@ class ResolverImpl(
10541055
}
10551056
}
10561057
// if substitution fails, fallback to the type from the property
1057-
return KSErrorType
1058+
return KSErrorType.fromReferenceBestEffort(property.type)
10581059
}
10591060

10601061
internal fun asMemberOf(
@@ -1247,7 +1248,7 @@ class ResolverImpl(
12471248
}
12481249

12491250
// Convert type arguments for Java wildcard, recursively.
1250-
private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType? {
1251+
private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType {
12511252
val parameters = constructor.parameters
12521253
val arguments = arguments
12531254

@@ -1258,16 +1259,18 @@ class ResolverImpl(
12581259
argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT
12591260
) {
12601261
// conflicting variances
1261-
// TODO: error message
1262-
return null
1262+
throw IllegalArgumentException(
1263+
"Conflicting variance: variance '${parameter.variance.label}' vs projection " +
1264+
"'${argument.projectionKind.label}'"
1265+
)
12631266
}
12641267

12651268
val argMode = mode.updateFromAnnotations(argument.type)
12661269
val variance = KotlinTypeMapper.getVarianceForWildcard(parameter, argument, argMode)
12671270
val genericMode = argMode.toGenericArgumentMode(
12681271
getEffectiveVariance(parameter.variance, argument.projectionKind)
12691272
)
1270-
TypeProjectionImpl(variance, argument.type.toWildcard(genericMode) ?: return null)
1273+
TypeProjectionImpl(variance, argument.type.toWildcard(genericMode))
12711274
}
12721275

12731276
return replace(wildcardArguments)
@@ -1369,19 +1372,17 @@ class ResolverImpl(
13691372
if (position == RefPosition.SUPER_TYPE &&
13701373
argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT
13711374
) {
1372-
// Type projection isn't allowed in immediate arguments to supertypes.
1373-
// TODO: error message
1374-
return KSTypeReferenceSyntheticImpl.getCached(KSErrorType, null)
1375+
throw IllegalArgumentException("Type projection isn't allowed in immediate arguments to supertypes")
13751376
}
13761377
}
13771378

1378-
val wildcardType = kotlinType.toWildcard(typeMappingMode)?.let {
1379+
val wildcardType = kotlinType.toWildcard(typeMappingMode).let {
13791380
var candidate: KotlinType = it
13801381
for (i in indexes.reversed()) {
13811382
candidate = candidate.arguments[i].type
13821383
}
13831384
getKSTypeCached(candidate)
1384-
} ?: KSErrorType
1385+
}
13851386

13861387
return KSTypeReferenceSyntheticImpl.getCached(wildcardType, null)
13871388
}

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSAnnotationDescriptorImpl.kt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
6262
import org.jetbrains.kotlin.name.ClassId
6363
import org.jetbrains.kotlin.name.FqName
6464
import org.jetbrains.kotlin.name.Name
65+
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
6566
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
67+
import org.jetbrains.kotlin.psi.KtExpression
6668
import org.jetbrains.kotlin.psi.KtParameter
6769
import org.jetbrains.kotlin.resolve.AnnotationResolverImpl
6870
import org.jetbrains.kotlin.resolve.BindingContext
@@ -161,7 +163,7 @@ private fun <T> ConstantValue<T>.toValue(parent: KSNode): Any? = when (this) {
161163
} else classValue.classId.findKSType()
162164
is KClassValue.Value.LocalClass -> getKSTypeCached(classValue.type)
163165
}
164-
is ErrorValue -> KSErrorType
166+
is ErrorValue -> KSErrorType(toString())
165167
is NullValue -> null
166168
else -> value
167169
}
@@ -211,7 +213,7 @@ fun LazyAnnotationDescriptor.getValueArguments(): Map<Name, ConstantValue<*>> {
211213
} else if (resolvedArgument is DefaultValueArgument) {
212214
valueParameter.name to DefaultConstantValue
213215
} else {
214-
c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument)?.let { value ->
216+
c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument).let { value ->
215217
val argExp = resolvedArgument.arguments.lastOrNull()?.getArgumentExpression()
216218
// When some elements are not available, the expected and actual size of an array argument will
217219
// be different. In such case, we need to reconstruct the array.
@@ -224,17 +226,22 @@ fun LazyAnnotationDescriptor.getValueArguments(): Map<Name, ConstantValue<*>> {
224226
val bc = ResolverImpl.instance!!.bindingTrace.bindingContext
225227
val args = argExp.innerExpressions.map {
226228
bc.get(BindingContext.COMPILE_TIME_VALUE, it)?.toConstantValue(value.type)
227-
?: ErrorValue.create("<ERROR VALUE>")
229+
?: it.asErrorValue()
228230
}
229231
valueParameter.name to TypedArrayValue(args, value.type)
230232
} else {
231-
valueParameter.name to value
233+
valueParameter.name to (value ?: argExp?.asErrorValue() ?: ErrorValue.create("ERROR VALUE"))
232234
}
233-
} ?: (valueParameter.name to ErrorValue.create("<ERROR VALUE>"))
235+
}
234236
}
235237
}.toMap()
236238
}
237239

240+
private fun KtExpression.asErrorValue(): ErrorValue {
241+
val reprExpr = (this as? KtClassLiteralExpression)?.receiverExpression ?: this
242+
return ErrorValue.create(reprExpr.text)
243+
}
244+
238245
fun AnnotationDescriptor.createKSValueArguments(ownerAnnotation: KSAnnotation): List<KSValueArgument> {
239246
val allValueArgs = if (this is LazyAnnotationDescriptor) {
240247
this.getValueArguments()
@@ -419,14 +426,14 @@ fun ValueParameterDescriptor.getDefaultValue(ownerAnnotation: KSAnnotation): Any
419426
if (!this.type.isError) {
420427
defaultValue?.convert(this.type)?.toValue(ownerAnnotation)
421428
} else {
422-
KSErrorType
429+
KSErrorType.fromKtErrorType(type)
423430
}
424431
}
425432
}
426433
is KtParameter -> if (!this.type.isError) {
427434
ResolverImpl.instance!!.evaluateConstant(psi.defaultValue, this.type)?.toValue(ownerAnnotation)
428435
} else {
429-
KSErrorType
436+
KSErrorType.fromKtErrorType(type)
430437
}
431438
is PsiAnnotationMethod -> {
432439
when (psi.defaultValue) {

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ class KSClassDeclarationDescriptorImpl private constructor(val descriptor: Class
153153
override fun asType(typeArguments: List<KSTypeArgument>): KSType =
154154
descriptor.defaultType.replaceTypeArguments(typeArguments)?.let {
155155
getKSTypeCached(it, typeArguments)
156-
} ?: KSErrorType
156+
} ?: KSErrorType()
157157

158158
override fun asStarProjectedType(): KSType {
159159
return getKSTypeCached(descriptor.defaultType.replaceArgumentsWithStarProjections())

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class KSClassDeclarationJavaEnumEntryImpl private constructor(val psi: PsiEnumCo
9797
// Enum can't have type parameters.
9898
override fun asType(typeArguments: List<KSTypeArgument>): KSType {
9999
if (typeArguments.isNotEmpty())
100-
return KSErrorType
100+
return KSErrorType()
101101
return asStarProjectedType()
102102
}
103103

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,13 @@ class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) :
157157
it.defaultType.replaceTypeArguments(typeArguments)?.let {
158158
getKSTypeCached(it, typeArguments)
159159
}
160-
} ?: KSErrorType
160+
} ?: KSErrorType()
161161
}
162162

163163
override fun asStarProjectedType(): KSType {
164164
return descriptor?.let {
165165
getKSTypeCached(it.defaultType.replaceArgumentsWithStarProjections())
166-
} ?: KSErrorType
166+
} ?: KSErrorType()
167167
}
168168

169169
override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceJavaImpl.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,13 @@ class KSTypeReferenceJavaImpl private constructor(val psi: PsiType, override val
124124
.mapNotNull {
125125
(it.annotationType.resolve() as? KSTypeImpl)?.kotlinType?.constructor?.declarationDescriptor?.fqNameSafe
126126
}
127-
val resolved = if ((resolvedType.declaration as? KSClassDeclarationDescriptorImpl)
128-
?.descriptor is NotFoundClasses.MockClassDescriptor
129-
) {
130-
KSErrorType
131-
} else resolvedType
127+
val resolved = when (val declaration = resolvedType.declaration) {
128+
is KSClassDeclarationDescriptorImpl -> when (val descriptor = declaration.descriptor) {
129+
is NotFoundClasses.MockClassDescriptor -> KSErrorType(descriptor.name.asString())
130+
else -> resolvedType
131+
}
132+
else -> resolvedType
133+
}
132134
val hasNotNull = relatedAnnotations.any { it in NOT_NULL_ANNOTATIONS }
133135
val hasNullable = relatedAnnotations.any { it in NULLABLE_ANNOTATIONS }
134136
return if (hasNullable && !hasNotNull) {

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceLiteJavaImpl.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ class KSTypeReferenceLiteJavaImpl private constructor(val psiElement: PsiElement
4747
val type: KSType by lazy {
4848
when (psiElement) {
4949
is PsiAnnotation -> {
50-
val psiClass = psiElement.nameReferenceElement!!.resolve() as? PsiClass
50+
val nameReferenceElement = psiElement.nameReferenceElement!!
51+
val psiClass = nameReferenceElement.resolve() as? PsiClass
5152
psiClass?.let {
5253
(psiElement.containingFile as? PsiJavaFile)?.let {
5354
ResolverImpl.instance!!.incrementalContext.recordLookup(it, psiClass.qualifiedName!!)
5455
}
5556
KSClassDeclarationJavaImpl.getCached(psiClass).asStarProjectedType()
56-
} ?: KSErrorType
57+
} ?: KSErrorType(nameReferenceElement.text)
5758
}
5859
is PsiMethod -> {
5960
KSClassDeclarationJavaImpl.getCached(psiElement.containingClass!!).asStarProjectedType()

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class KSClassDeclarationImpl private constructor(val ktClassOrObject: KtClassOrO
124124
override fun asType(typeArguments: List<KSTypeArgument>): KSType {
125125
return descriptor.defaultType.replaceTypeArguments(typeArguments)?.let {
126126
getKSTypeCached(it, typeArguments)
127-
} ?: KSErrorType
127+
} ?: KSErrorType()
128128
}
129129

130130
override fun asStarProjectedType(): KSType {

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,28 @@ package com.google.devtools.ksp.symbol.impl.kotlin
1919

2020
import com.google.devtools.ksp.symbol.*
2121
import com.google.devtools.ksp.symbol.impl.synthetic.KSErrorTypeClassDeclaration
22+
import org.jetbrains.kotlin.types.FlexibleType
23+
import org.jetbrains.kotlin.types.KotlinType
24+
import org.jetbrains.kotlin.types.error.ErrorType
25+
import org.jetbrains.kotlin.types.error.ErrorTypeKind
2226

23-
object KSErrorType : KSType {
24-
override val annotations: Sequence<KSAnnotation> = emptySequence()
27+
class KSErrorType(
28+
val nameHint: String? = null,
29+
) : KSType {
30+
override val annotations: Sequence<KSAnnotation>
31+
get() = emptySequence()
2532

26-
override val arguments: List<KSTypeArgument> = emptyList()
33+
override val arguments: List<KSTypeArgument>
34+
get() = emptyList()
2735

28-
override val declaration: KSDeclaration = KSErrorTypeClassDeclaration
36+
override val declaration: KSDeclaration
37+
get() = KSErrorTypeClassDeclaration(this)
2938

30-
override val isError: Boolean = true
39+
override val isError: Boolean
40+
get() = true
3141

32-
override val nullability: Nullability = Nullability.NULLABLE
42+
override val nullability: Nullability
43+
get() = Nullability.NULLABLE
3344

3445
override fun isAssignableFrom(that: KSType): Boolean {
3546
return false
@@ -51,7 +62,8 @@ object KSErrorType : KSType {
5162
return this
5263
}
5364

54-
override val isMarkedNullable: Boolean = false
65+
override val isMarkedNullable: Boolean
66+
get() = false
5567

5668
override fun replace(arguments: List<KSTypeArgument>): KSType {
5769
return this
@@ -61,11 +73,51 @@ object KSErrorType : KSType {
6173
return this
6274
}
6375

64-
override fun toString(): String {
65-
return "<ERROR TYPE>"
66-
}
76+
override fun toString(): String = nameHint?.let { "<ERROR TYPE: $it>" } ?: "<ERROR TYPE>"
77+
78+
override val isFunctionType: Boolean
79+
get() = false
80+
81+
override val isSuspendFunctionType: Boolean
82+
get() = false
6783

68-
override val isFunctionType: Boolean = false
84+
override fun hashCode() = nameHint.hashCode()
6985

70-
override val isSuspendFunctionType: Boolean = false
86+
override fun equals(other: Any?): Boolean {
87+
return this === other || other is KSErrorType && other.nameHint == nameHint
88+
}
89+
90+
companion object {
91+
fun fromReferenceBestEffort(reference: KSTypeReference?): KSErrorType {
92+
return when (val type = reference?.resolve()) {
93+
is KSErrorType -> type
94+
null -> KSErrorType(reference?.element?.toString())
95+
else -> KSErrorType(type.toString())
96+
}
97+
}
98+
99+
fun fromKtErrorType(ktType: KotlinType): KSErrorType {
100+
// Logic is in sync with `KotlinType.isError`
101+
val errorType: ErrorType = when (val unwrapped = ktType.unwrap()) {
102+
is ErrorType -> unwrapped
103+
is FlexibleType -> unwrapped.delegate as? ErrorType
104+
else -> null
105+
} ?: throw IllegalArgumentException("Not an error type: $ktType")
106+
107+
val hint = when (errorType.kind) {
108+
// Handle "Unresolved types" group
109+
ErrorTypeKind.UNRESOLVED_TYPE,
110+
ErrorTypeKind.UNRESOLVED_CLASS_TYPE,
111+
ErrorTypeKind.UNRESOLVED_JAVA_CLASS,
112+
ErrorTypeKind.UNRESOLVED_DECLARATION,
113+
ErrorTypeKind.UNRESOLVED_KCLASS_CONSTANT_VALUE,
114+
ErrorTypeKind.UNRESOLVED_TYPE_ALIAS -> errorType.formatParams.first()
115+
116+
// TODO: Handle more ErrorTypeKinds where it's possible to extract a name for the error type.
117+
else -> errorType.debugMessage
118+
}
119+
120+
return KSErrorType(hint)
121+
}
122+
}
71123
}

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionErrorImpl.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,19 @@ class KSFunctionErrorImpl(
2929
) : KSFunction {
3030
override val isError: Boolean = true
3131

32-
override val returnType: KSType = KSErrorType
32+
override val returnType: KSType
33+
get() = KSErrorType.fromReferenceBestEffort(declaration.returnType)
3334

3435
override val parameterTypes: List<KSType?>
3536
get() = declaration.parameters.map {
36-
KSErrorType
37+
KSErrorType.fromReferenceBestEffort(it.type)
3738
}
3839
override val typeParameters: List<KSTypeParameter>
3940
get() = emptyList()
4041

4142
override val extensionReceiverType: KSType?
4243
get() = declaration.extensionReceiver?.let {
43-
KSErrorType
44+
KSErrorType.fromReferenceBestEffort(it)
4445
}
4546

4647
override fun equals(other: Any?): Boolean {

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class KSPropertyDeclarationImpl private constructor(val ktProperty: KtProperty)
9797
KSTypeReferenceDeferredImpl.getCached(this) {
9898
val desc = propertyDescriptor as? VariableDescriptorWithAccessors
9999
if (desc == null) {
100-
KSErrorType
100+
KSErrorType()
101101
} else {
102102
getKSTypeCached(desc.type)
103103
}

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class KSTypeImpl private constructor(
9797
override fun replace(arguments: List<KSTypeArgument>): KSType {
9898
return kotlinType.replaceTypeArguments(arguments)?.let {
9999
getKSTypeCached(it, arguments, annotations)
100-
} ?: KSErrorType
100+
} ?: KSErrorType()
101101
}
102102

103103
override fun starProjection(): KSType {
@@ -136,10 +136,12 @@ fun getKSTypeCached(
136136
ksTypeArguments: List<KSTypeArgument>? = null,
137137
annotations: Sequence<KSAnnotation> = sequenceOf()
138138
): KSType {
139-
return if (kotlinType.isError ||
140-
kotlinType.constructor.declarationDescriptor is NotFoundClasses.MockClassDescriptor
141-
) {
142-
KSErrorType
139+
if (kotlinType.isError) {
140+
return KSErrorType.fromKtErrorType(kotlinType)
141+
}
142+
val descriptor = kotlinType.constructor.declarationDescriptor
143+
return if (descriptor is NotFoundClasses.MockClassDescriptor) {
144+
KSErrorType(descriptor.name.asString())
143145
} else {
144146
KSTypeImpl.getCached(
145147
kotlinType,

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class KSValueParameterImpl private constructor(val ktParameter: KtParameter) : K
112112

113113
override val type: KSTypeReference by lazy {
114114
ktParameter.typeReference?.let { KSTypeReferenceImpl.getCached(it) }
115-
?: findPropertyForAccessor()?.type ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType, this)
115+
?: findPropertyForAccessor()?.type ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType(), this)
116116
}
117117

118118
override val hasDefault: Boolean = ktParameter.hasDefaultValue()

0 commit comments

Comments
 (0)