diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/common/ErrorTypeUtils.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/common/ErrorTypeUtils.kt new file mode 100644 index 0000000000..70b67fd8b6 --- /dev/null +++ b/common-util/src/main/kotlin/com/google/devtools/ksp/common/ErrorTypeUtils.kt @@ -0,0 +1,24 @@ +package com.google.devtools.ksp.common + +import com.google.devtools.ksp.symbol.KSType +import com.google.devtools.ksp.symbol.KSTypeArgument + +inline fun errorTypeOnInconsistentArguments( + arguments: List, + placeholdersProvider: () -> List, + withCorrectedArguments: (corrected: List) -> KSType, + errorType: (name: String, message: String) -> E, +): E? { + if (arguments.isNotEmpty()) { + val placeholders = placeholdersProvider() + val diff = arguments.size - placeholders.size + if (diff > 0) { + val wouldBeType = withCorrectedArguments(arguments.dropLast(diff)) + return errorType(wouldBeType.toString(), "Unexpected extra $diff type argument(s)") + } else if (diff < 0) { + val wouldBeType = withCorrectedArguments(arguments + placeholders.drop(arguments.size)) + return errorType(wouldBeType.toString(), "Missing ${-diff} type argument(s)") + } + } + return null +} diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt index cb6640a66c..9a24d49b66 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt @@ -1248,7 +1248,7 @@ class ResolverImpl( } // Convert type arguments for Java wildcard, recursively. - private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType { + private fun KotlinType.toWildcard(mode: TypeMappingMode): Result { val parameters = constructor.parameters val arguments = arguments @@ -1258,10 +1258,11 @@ class ResolverImpl( parameter.variance != org.jetbrains.kotlin.types.Variance.INVARIANT && argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT ) { - // conflicting variances - throw IllegalArgumentException( - "Conflicting variance: variance '${parameter.variance.label}' vs projection " + - "'${argument.projectionKind.label}'" + return Result.failure( + IllegalArgumentException( + "Conflicting variance: variance '${parameter.variance.label}' vs projection " + + "'${argument.projectionKind.label}'" + ) ) } @@ -1270,10 +1271,10 @@ class ResolverImpl( val genericMode = argMode.toGenericArgumentMode( getEffectiveVariance(parameter.variance, argument.projectionKind) ) - TypeProjectionImpl(variance, argument.type.toWildcard(genericMode)) + TypeProjectionImpl(variance, argument.type.toWildcard(genericMode).getOrElse { return Result.failure(it) }) } - return replace(wildcardArguments) + return Result.success(replace(wildcardArguments)) } private val JVM_SUPPRESS_WILDCARDS_NAME = KSNameImpl.getCached("kotlin.jvm.JvmSuppressWildcards") @@ -1372,12 +1373,19 @@ class ResolverImpl( if (position == RefPosition.SUPER_TYPE && argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT ) { - throw IllegalArgumentException("Type projection isn't allowed in immediate arguments to supertypes") + val errorType = KSErrorType( + name = type.toString(), + message = "Type projection isn't allowed in immediate arguments to supertypes" + ) + return KSTypeReferenceSyntheticImpl.getCached(errorType, null) } } val wildcardType = kotlinType.toWildcard(typeMappingMode).let { - var candidate: KotlinType = it + var candidate: KotlinType = it.getOrElse { error -> + val errorType = KSErrorType(name = type.toString(), message = error.message) + return KSTypeReferenceSyntheticImpl.getCached(errorType, null) + } for (i in indexes.reversed()) { candidate = candidate.arguments[i].type } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt index f1cb2c74bb..b0ca39976b 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt @@ -151,9 +151,7 @@ class KSClassDeclarationDescriptorImpl private constructor(val descriptor: Class } override fun asType(typeArguments: List): KSType = - descriptor.defaultType.replaceTypeArguments(typeArguments)?.let { - getKSTypeCached(it, typeArguments) - } ?: KSErrorType() + descriptor.defaultType.replaceTypeArguments(typeArguments) override fun asStarProjectedType(): KSType { return getKSTypeCached(descriptor.defaultType.replaceArgumentsWithStarProjections()) diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt index 337ce251b7..db0a43188f 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt @@ -17,6 +17,7 @@ package com.google.devtools.ksp.symbol.impl.java +import com.google.devtools.ksp.common.errorTypeOnInconsistentArguments import com.google.devtools.ksp.common.impl.KSNameImpl import com.google.devtools.ksp.common.toKSModifiers import com.google.devtools.ksp.processing.impl.KSObjectCache @@ -96,8 +97,10 @@ class KSClassDeclarationJavaEnumEntryImpl private constructor(val psi: PsiEnumCo // Enum can't have type parameters. override fun asType(typeArguments: List): KSType { - if (typeArguments.isNotEmpty()) - return KSErrorType() + errorTypeOnInconsistentArguments( + arguments = typeArguments, placeholdersProvider = ::emptyList, + withCorrectedArguments = ::asType, errorType = ::KSErrorType, + )?.let { error -> return error } return asStarProjectedType() } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt index 2a0481dea4..b46bed8559 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt @@ -153,17 +153,13 @@ class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) : } override fun asType(typeArguments: List): KSType { - return descriptor?.let { - it.defaultType.replaceTypeArguments(typeArguments)?.let { - getKSTypeCached(it, typeArguments) - } - } ?: KSErrorType() + return descriptor?.defaultType?.replaceTypeArguments(typeArguments) ?: KSErrorType(psi.qualifiedName) } override fun asStarProjectedType(): KSType { return descriptor?.let { getKSTypeCached(it.defaultType.replaceArgumentsWithStarProjections()) - } ?: KSErrorType() + } ?: KSErrorType(psi.qualifiedName) } override fun accept(visitor: KSVisitor, data: D): R { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt index 393a679469..3979da1a4b 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt @@ -122,9 +122,7 @@ class KSClassDeclarationImpl private constructor(val ktClassOrObject: KtClassOrO } override fun asType(typeArguments: List): KSType { - return descriptor.defaultType.replaceTypeArguments(typeArguments)?.let { - getKSTypeCached(it, typeArguments) - } ?: KSErrorType() + return descriptor.defaultType.replaceTypeArguments(typeArguments) } override fun asStarProjectedType(): KSType { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt index c911474b02..9c5e6ef508 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt @@ -25,8 +25,12 @@ import org.jetbrains.kotlin.types.error.ErrorType import org.jetbrains.kotlin.types.error.ErrorTypeKind class KSErrorType( - val nameHint: String? = null, + val nameHint: String?, ) : KSType { + constructor(name: String, message: String?) : this( + nameHint = listOfNotNull(name, message).takeIf { it.isNotEmpty() }?.joinToString(" % ") + ) + override val annotations: Sequence get() = emptySequence() diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt index 0ea15def59..8094ab1ced 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt @@ -97,7 +97,7 @@ class KSPropertyDeclarationImpl private constructor(val ktProperty: KtProperty) KSTypeReferenceDeferredImpl.getCached(this) { val desc = propertyDescriptor as? VariableDescriptorWithAccessors if (desc == null) { - KSErrorType() + KSErrorType(null /* no info available */) } else { getKSTypeCached(desc.type) } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt index 62f8b90cb1..5fff631c6a 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt @@ -95,9 +95,7 @@ class KSTypeImpl private constructor( } override fun replace(arguments: List): KSType { - return kotlinType.replaceTypeArguments(arguments)?.let { - getKSTypeCached(it, arguments, annotations) - } ?: KSErrorType() + return kotlinType.replaceTypeArguments(arguments, annotations) } override fun starProjection(): KSType { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt index 5e95a12904..5a2d0853bf 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt @@ -112,7 +112,8 @@ 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(null /* no info available */), this) } override val hasDefault: Boolean = ktParameter.hasDefaultValue() diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt index e8ab1fb8ac..47cdb9c256 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt @@ -18,6 +18,7 @@ package com.google.devtools.ksp.symbol.impl import com.google.devtools.ksp.ExceptionMessage import com.google.devtools.ksp.KspExperimental +import com.google.devtools.ksp.common.errorTypeOnInconsistentArguments import com.google.devtools.ksp.common.impl.KSNameImpl import com.google.devtools.ksp.processing.impl.ResolverImpl import com.google.devtools.ksp.symbol.* @@ -136,10 +137,18 @@ fun org.jetbrains.kotlin.types.Variance.toKSVariance(): Variance { private fun KSTypeReference.toKotlinType() = (resolve() as? KSTypeImpl)?.kotlinType -// returns null if error -internal fun KotlinType.replaceTypeArguments(newArguments: List): KotlinType? { - if (newArguments.isNotEmpty() && this.arguments.size != newArguments.size) - return null +// returns KSErrorType if error +internal fun KotlinType.replaceTypeArguments( + newArguments: List, + annotations: Sequence = emptySequence(), +): KSType { + errorTypeOnInconsistentArguments( + arguments = newArguments, + placeholdersProvider = { arguments.map { KSTypeArgumentDescriptorImpl.getCached(it, Origin.SYNTHETIC, null) } }, + withCorrectedArguments = ::replaceTypeArguments, + errorType = ::KSErrorType, + )?.let { error -> return error } + return replace( newArguments.mapIndexed { index, ksTypeArgument -> val variance = when (ksTypeArgument.variance) { @@ -155,11 +164,11 @@ internal fun KotlinType.replaceTypeArguments(newArguments: List) else -> throw IllegalStateException( "Unexpected psi for type argument: ${ksTypeArgument.javaClass}, $ExceptionMessage" ) - }.toKotlinType() ?: return null + }.let { it.toKotlinType() ?: return KSErrorType.fromReferenceBestEffort(it) } TypeProjectionImpl(variance, type) } - ) + ).let { KSTypeImpl.getCached(it, newArguments, annotations) } } internal fun FunctionDescriptor.toKSDeclaration(): KSDeclaration { diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt index 6311ec3e0a..0030d5f088 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt @@ -18,6 +18,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.KSObjectCache +import com.google.devtools.ksp.common.errorTypeOnInconsistentArguments import com.google.devtools.ksp.common.impl.KSNameImpl import com.google.devtools.ksp.common.impl.KSTypeReferenceSyntheticImpl import com.google.devtools.ksp.impl.ResolverAAImpl @@ -124,9 +125,12 @@ class KSClassDeclarationImpl private constructor(internal val ktClassOrObjectSym } override fun asType(typeArguments: List): KSType { - if (typeArguments.isNotEmpty() && typeArguments.size != asStarProjectedType().arguments.size) { - return KSErrorType() - } + errorTypeOnInconsistentArguments( + arguments = typeArguments, + placeholdersProvider = { asStarProjectedType().arguments }, + withCorrectedArguments = ::asType, + errorType = ::KSErrorType, + )?.let { error -> return error } return analyze { if (typeArguments.isEmpty()) { typeParameters.map { buildTypeParameterType((it as KSTypeParameterImpl).ktTypeParameterSymbol) } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt index 24dbfb7236..83e40c4700 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt @@ -19,8 +19,12 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.symbol.* class KSErrorType( - private val hint: String? = null, + private val hint: String?, ) : KSType { + constructor(name: String, message: String?) : this( + hint = listOfNotNull(name, message).takeIf { it.isNotEmpty() }?.joinToString(" % ") + ) + override val declaration: KSDeclaration get() = KSErrorTypeClassDeclaration(this) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt index ffc26dca3a..1831ce1bd7 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt @@ -114,7 +114,7 @@ class KSErrorTypeClassDeclaration( return this === other || other is KSErrorTypeClassDeclaration && other.type == type } - override fun hashCode(): Int = type.hashCode() + override fun hashCode(): Int = type.hashCode() * 2 override val docString get() = null diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt index 0a4ee80c07..4a9b8a3de1 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt @@ -19,6 +19,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.IdKeyPair import com.google.devtools.ksp.common.KSObjectCache +import com.google.devtools.ksp.common.errorTypeOnInconsistentArguments import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.impl.recordLookupWithSupertypes import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeArgumentResolvedImpl @@ -110,12 +111,17 @@ class KSTypeImpl private constructor(internal val type: KtType) : KSType { } override fun replace(arguments: List): KSType { - return type.replace(arguments.map { it.toKtTypeProjection() })?.let { getCached(it) } ?: KSErrorType() + errorTypeOnInconsistentArguments( + arguments = arguments, + placeholdersProvider = { type.typeArguments().map { KSTypeArgumentResolvedImpl.getCached(it) } }, + withCorrectedArguments = ::replace, + errorType = ::KSErrorType, + )?.let { error -> return error } + return getCached(type.replace(arguments.map { it.toKtTypeProjection() })) } override fun starProjection(): KSType { - return type.replace(List(type.typeArguments().size) { KtStarTypeProjection(type.token) }) - ?.let { getCached(it) } ?: KSErrorType() + return getCached(type.replace(List(type.typeArguments().size) { KtStarTypeProjection(type.token) })) } override fun makeNullable(): KSType { @@ -134,7 +140,8 @@ class KSTypeImpl private constructor(internal val type: KtType) : KSType { get() = type.nullability == KtTypeNullability.NULLABLE override val isError: Boolean - get() = type is KtErrorType + // TODO: non exist type returns KtNonErrorClassType, check upstream for KtClassErrorType usage. + get() = type is KtErrorType || type.classifierSymbol() == null override val isFunctionType: Boolean get() = type is KtFunctionalType && !type.isSuspend diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeReferenceResolvedImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeReferenceResolvedImpl.kt index c449f275ec..c1473d2a89 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeReferenceResolvedImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeReferenceResolvedImpl.kt @@ -22,14 +22,11 @@ import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.impl.recordLookup import com.google.devtools.ksp.impl.symbol.kotlin.Deferrable import com.google.devtools.ksp.impl.symbol.kotlin.KSClassDeclarationImpl -import com.google.devtools.ksp.impl.symbol.kotlin.KSErrorType import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeImpl import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeParameterImpl import com.google.devtools.ksp.impl.symbol.kotlin.Restorable import com.google.devtools.ksp.impl.symbol.kotlin.analyze import com.google.devtools.ksp.impl.symbol.kotlin.annotations -import com.google.devtools.ksp.impl.symbol.kotlin.classifierSymbol -import com.google.devtools.ksp.impl.symbol.kotlin.getNameHint import com.google.devtools.ksp.impl.symbol.kotlin.render import com.google.devtools.ksp.impl.symbol.kotlin.toClassifierReference import com.google.devtools.ksp.impl.symbol.kotlin.toLocation @@ -61,22 +58,7 @@ class KSTypeReferenceResolvedImpl private constructor( override fun resolve(): KSType { analyze { recordLookup(ktType, parent) } - // TODO: non exist type returns KtNonErrorClassType, check upstream for KtClassErrorType usage. - return if ( - analyze { - ktType is KtClassErrorType || (ktType.classifierSymbol() == null) - } - ) { - KSErrorType( - when (ktType) { - is KtClassErrorType -> ktType.getNameHint() - is KtTypeErrorType -> null // No info available - else -> ktType.render() - } - ) - } else { - KSTypeImpl.getCached(ktType) - } + return KSTypeImpl.getCached(ktType) } override val annotations: Sequence by lazy { diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt index 49fa2c0acd..177aeeacf3 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt @@ -62,7 +62,6 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.toFirExpression -import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedError import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.types.ConeClassLikeType @@ -148,22 +147,6 @@ internal fun KtAnnotationValue.render(): String { } } -internal fun KtClassErrorType.getNameHint(): String { - return when (val coneType = (this as KtFirType).coneType) { - is ConeErrorType -> when (val diagnostic = coneType.diagnostic) { - is ConeUnresolvedError -> diagnostic.qualifier - else -> throw IllegalStateException("Unexpected diagnostic: ${diagnostic.reason}") - } - is ConeClassLikeType -> { - coneType.lookupTag.name.asString() - } - else -> { - // KtFirClassErrorType has `coneType: ConeClassLikeType`, so we're safe as long as that doesn't change - throw IllegalStateException("Unexpected coneType: $coneType") - } - } -} - internal fun KtType.render(inFunctionType: Boolean = false): String { return buildString { annotations.forEach { @@ -194,8 +177,8 @@ internal fun KtType.render(inFunctionType: Boolean = false): String { } } } - is KtClassErrorType -> KSErrorType(getNameHint()).toString() - is KtTypeErrorType -> KSErrorType().toString() + is KtClassErrorType -> KSErrorType(qualifiers.joinToString(".") { it.name.asString() }).toString() + is KtTypeErrorType -> KSErrorType(tryRenderAsNonErrorType()).toString() is KtCapturedType -> asStringForDebugging() is KtDefinitelyNotNullType -> original.render(inFunctionType) + " & Any" is KtDynamicType -> "" @@ -661,10 +644,8 @@ internal fun KtType.isAssignableFrom(that: KtType): Boolean { } // TODO: fix flexible type creation once upstream available. -internal fun KtType.replace(newArgs: List): KtType? { - if (newArgs.isNotEmpty() && newArgs.size != this.typeArguments().size) { - return null - } +internal fun KtType.replace(newArgs: List): KtType { + require(newArgs.isEmpty() || newArgs.size == this.typeArguments().size) return analyze { when (val symbol = classifierSymbol()) { is KtClassLikeSymbol -> analysisSession.buildClassType(symbol) { diff --git a/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt b/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt index 20cb7f2e81..36a715e32a 100644 --- a/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt +++ b/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt @@ -38,65 +38,65 @@ // JL.asType([INVARIANT Int, INVARIANT String]): JL // JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): JL<, > // JL.asType(emptyList()): JL -// KS1.star.replace([INVARIANT Int, INVARIANT String]): -// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KS1.asType([INVARIANT Int, INVARIANT String]): -// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KS1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> +// KS1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> // KS1.asType(emptyList()): KS1 -// KL1.star.replace([INVARIANT Int, INVARIANT String]): -// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KL1.asType([INVARIANT Int, INVARIANT String]): -// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KL1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> +// KL1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> // KL1.asType(emptyList()): KL1 -// JS1.star.replace([INVARIANT Int, INVARIANT String]): -// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JS1.asType([INVARIANT Int, INVARIANT String]): -// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JS1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> +// JS1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> // JS1.asType(emptyList()): JS1 -// JL1.star.replace([INVARIANT Int, INVARIANT String]): -// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JL1.asType([INVARIANT Int, INVARIANT String]): -// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JL1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> +// JL1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> // JL1.asType(emptyList()): JL1 -// JSE.star.replace([INVARIANT Int, INVARIANT String]): -// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JSE.asType([INVARIANT Int, INVARIANT String]): -// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.star.replace([INVARIANT Int, INVARIANT String]): +// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.asType([INVARIANT Int, INVARIANT String]): +// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JSE.asType(emptyList()): JSE -// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): -// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JSE.E.asType([INVARIANT Int, INVARIANT String]): -// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): +// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.E.asType([INVARIANT Int, INVARIANT String]): +// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JSE.E.asType(emptyList()): JSE -// JLE.star.replace([INVARIANT Int, INVARIANT String]): -// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JLE.asType([INVARIANT Int, INVARIANT String]): -// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.star.replace([INVARIANT Int, INVARIANT String]): +// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.asType([INVARIANT Int, INVARIANT String]): +// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JLE.asType(emptyList()): JLE -// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): -// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JLE.E.asType([INVARIANT Int, INVARIANT String]): -// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): +// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.E.asType([INVARIANT Int, INVARIANT String]): +// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JLE.E.asType(emptyList()): JLE -// KSE.star.replace([INVARIANT Int, INVARIANT String]): -// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KSE.asType([INVARIANT Int, INVARIANT String]): -// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.star.replace([INVARIANT Int, INVARIANT String]): +// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.asType([INVARIANT Int, INVARIANT String]): +// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KSE.asType(emptyList()): KSE -// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): -// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KSE.E.asType([INVARIANT Int, INVARIANT String]): -// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): +// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.E.asType([INVARIANT Int, INVARIANT String]): +// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KSE.E.asType(emptyList()): KSE -// KLE.star.replace([INVARIANT Int, INVARIANT String]): -// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KLE.asType([INVARIANT Int, INVARIANT String]): -// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.star.replace([INVARIANT Int, INVARIANT String]): +// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.asType([INVARIANT Int, INVARIANT String]): +// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KLE.asType(emptyList()): KLE -// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): -// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KLE.E.asType([INVARIANT Int, INVARIANT String]): -// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): +// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.E.asType([INVARIANT Int, INVARIANT String]): +// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KLE.E.asType(emptyList()): KLE // default type:A // flexible type star:T diff --git a/test-utils/testData/api/replaceWithErrorTypeArgs.kt b/test-utils/testData/api/replaceWithErrorTypeArgs.kt index 1ac869ae4b..58555c0c1d 100644 --- a/test-utils/testData/api/replaceWithErrorTypeArgs.kt +++ b/test-utils/testData/api/replaceWithErrorTypeArgs.kt @@ -19,84 +19,84 @@ // TEST PROCESSOR: ReplaceWithErrorTypeArgsProcessor // EXPECTED: // KS.star.replace([INVARIANT Int, INVARIANT String]): KS -// KS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): // KS.asType([INVARIANT Int, INVARIANT String]): KS -// KS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KS.asType(emptyList()): KS // KL.star.replace([INVARIANT Int, INVARIANT String]): KL -// KL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): // KL.asType([INVARIANT Int, INVARIANT String]): KL -// KL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KL.asType(emptyList()): KL // JS.star.replace([INVARIANT Int, INVARIANT String]): JS -// JS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): // JS.asType([INVARIANT Int, INVARIANT String]): JS -// JS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JS.asType(emptyList()): JS // JL.star.replace([INVARIANT Int, INVARIANT String]): JL -// JL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): // JL.asType([INVARIANT Int, INVARIANT String]): JL -// JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JL.asType(emptyList()): JL -// KS1.star.replace([INVARIANT Int, INVARIANT String]): -// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KS1.asType([INVARIANT Int, INVARIANT String]): -// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KS1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> +// KS1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> // KS1.asType(emptyList()): KS1 -// KL1.star.replace([INVARIANT Int, INVARIANT String]): -// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KL1.asType([INVARIANT Int, INVARIANT String]): -// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KL1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> +// KL1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> // KL1.asType(emptyList()): KL1 -// JS1.star.replace([INVARIANT Int, INVARIANT String]): -// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JS1.asType([INVARIANT Int, INVARIANT String]): -// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JS1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> +// JS1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> // JS1.asType(emptyList()): JS1 -// JL1.star.replace([INVARIANT Int, INVARIANT String]): -// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JL1.asType([INVARIANT Int, INVARIANT String]): -// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JL1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> +// JL1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> // JL1.asType(emptyList()): JL1 -// JSE.star.replace([INVARIANT Int, INVARIANT String]): -// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JSE.asType([INVARIANT Int, INVARIANT String]): -// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.star.replace([INVARIANT Int, INVARIANT String]): +// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.asType([INVARIANT Int, INVARIANT String]): +// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JSE.asType(emptyList()): JSE -// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): -// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JSE.E.asType([INVARIANT Int, INVARIANT String]): -// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): +// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.E.asType([INVARIANT Int, INVARIANT String]): +// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JSE.E.asType(emptyList()): JSE.E -// JLE.star.replace([INVARIANT Int, INVARIANT String]): -// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JLE.asType([INVARIANT Int, INVARIANT String]): -// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.star.replace([INVARIANT Int, INVARIANT String]): +// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.asType([INVARIANT Int, INVARIANT String]): +// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JLE.asType(emptyList()): JLE -// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): -// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JLE.E.asType([INVARIANT Int, INVARIANT String]): -// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): +// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.E.asType([INVARIANT Int, INVARIANT String]): +// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JLE.E.asType(emptyList()): JLE.E -// KSE.star.replace([INVARIANT Int, INVARIANT String]): -// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KSE.asType([INVARIANT Int, INVARIANT String]): -// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.star.replace([INVARIANT Int, INVARIANT String]): +// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.asType([INVARIANT Int, INVARIANT String]): +// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KSE.asType(emptyList()): KSE -// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): -// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KSE.E.asType([INVARIANT Int, INVARIANT String]): -// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): +// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.E.asType([INVARIANT Int, INVARIANT String]): +// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KSE.E.asType(emptyList()): E -// KLE.star.replace([INVARIANT Int, INVARIANT String]): -// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KLE.asType([INVARIANT Int, INVARIANT String]): -// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.star.replace([INVARIANT Int, INVARIANT String]): +// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.asType([INVARIANT Int, INVARIANT String]): +// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KLE.asType(emptyList()): KLE -// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): -// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KLE.E.asType([INVARIANT Int, INVARIANT String]): -// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): +// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.E.asType([INVARIANT Int, INVARIANT String]): +// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KLE.E.asType(emptyList()): KLE.E // default type:A // flexible type star:(T..T?)