Diagnostics for type alias expansion errors in type alias RHS
This commit is contained in:
@@ -118,7 +118,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtTypeParameterList> GENERIC_THROWABLE_SUBCLASS = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<PsiElement> UNSUPPORTED_TYPEALIAS = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<KtUserType, ClassifierDescriptor> RECURSIVE_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtElement, ClassifierDescriptor> RECURSIVE_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory3<KtElement, KotlinType, KotlinType, ClassifierDescriptor> UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION =
|
||||
DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory1<KtElement, KotlinType> CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
@@ -151,6 +152,8 @@ class DeclarationsChecker(
|
||||
private fun checkTypeAliasDeclaration(typeAliasDescriptor: TypeAliasDescriptor, declaration: KtTypeAlias) {
|
||||
val typeReference = declaration.getTypeReference() ?: return
|
||||
|
||||
checkTypeAliasExpansion(typeAliasDescriptor, declaration)
|
||||
|
||||
val expandedType = typeAliasDescriptor.expandedType // TODO refactor type alias expansion
|
||||
if (expandedType.isError) return
|
||||
|
||||
@@ -161,6 +164,40 @@ class DeclarationsChecker(
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeAliasDeclarationCheckingReportStrategy(
|
||||
private val trace: BindingTrace,
|
||||
typeAliasDescriptor: TypeAliasDescriptor,
|
||||
declaration: KtTypeAlias
|
||||
) : TypeAliasExpansionReportStrategy {
|
||||
private val typeReference = declaration.getTypeReference()
|
||||
?: throw AssertionError("Incorrect type alias declaration for $typeAliasDescriptor")
|
||||
|
||||
override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {
|
||||
// Do nothing: this should've been reported during type resolution.
|
||||
}
|
||||
|
||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {
|
||||
trace.report(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION.on(typeReference, substitutedArgument))
|
||||
}
|
||||
|
||||
override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) {
|
||||
trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(typeReference, typeAlias))
|
||||
}
|
||||
|
||||
override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {
|
||||
// TODO more precise diagnostics
|
||||
if (!argument.dependsOnTypeAliasParameters() && !bound.dependsOnTypeAliasParameters()) {
|
||||
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkTypeAliasExpansion(typeAliasDescriptor: TypeAliasDescriptor, declaration: KtTypeAlias) {
|
||||
val typeAliasExpansion = TypeAliasExpansion.createWithFormalArguments(typeAliasDescriptor)
|
||||
val reportStrategy = TypeAliasDeclarationCheckingReportStrategy(trace, typeAliasDescriptor, declaration)
|
||||
TypeAliasExpander(reportStrategy).expandWithoutAbbreviation(typeAliasExpansion, Annotations.EMPTY)
|
||||
}
|
||||
|
||||
private fun checkConstructorDeclaration(constructorDescriptor: ConstructorDescriptor, declaration: KtDeclaration) {
|
||||
declaration.checkTypeReferences()
|
||||
modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor)
|
||||
|
||||
@@ -96,7 +96,7 @@ class TypeAliasExpander(
|
||||
argumentVariance
|
||||
else {
|
||||
if (originalVariance != argumentVariance && !typeAliasArgument.isStarProjection) {
|
||||
reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, originalType)
|
||||
reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, typeAliasArgument.type)
|
||||
}
|
||||
argumentVariance
|
||||
}
|
||||
|
||||
+2
-2
@@ -22,13 +22,13 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface TypeAliasExpansionReportStrategy {
|
||||
fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int)
|
||||
fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, expandingType: KotlinType)
|
||||
fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType)
|
||||
fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor)
|
||||
fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor)
|
||||
|
||||
object DO_NOTHING : TypeAliasExpansionReportStrategy {
|
||||
override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {}
|
||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, expandingType: KotlinType) {}
|
||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {}
|
||||
override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) {}
|
||||
override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {}
|
||||
}
|
||||
|
||||
@@ -400,14 +400,12 @@ class TypeResolver(
|
||||
// This is not intended to be used in normal users' environments, only for tests and debugger etc
|
||||
typeTransformerForTests.transformType(resultingType)?.let { return type(it) }
|
||||
|
||||
if (c.checkBounds) {
|
||||
if (c.checkBounds && !resultingType.dependsOnTypeAliasParameters()) {
|
||||
val substitutor = TypeSubstitutor.create(resultingType)
|
||||
for (i in parameters.indices) {
|
||||
val parameter = parameters[i]
|
||||
val argument = arguments[i].type
|
||||
|
||||
if (argument.dependsOnTypeAliasParameters()) continue
|
||||
|
||||
val typeReference = collectedArgumentAsTypeProjections.getOrNull(i)?.typeReference
|
||||
|
||||
if (typeReference != null) {
|
||||
@@ -495,7 +493,7 @@ class TypeResolver(
|
||||
}
|
||||
}
|
||||
|
||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, expandingType: KotlinType) {
|
||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {
|
||||
val argumentElement = typeParameter?.let { mappedArguments[it] }
|
||||
if (argumentElement != null && typeParameter != null) {
|
||||
trace.report(CONFLICTING_PROJECTION.on(argumentElement, typeParameter))
|
||||
|
||||
@@ -595,16 +595,23 @@ class CandidateResolver(
|
||||
ktTypeArguments: List<KtTypeProjection>,
|
||||
private val trace: BindingTrace
|
||||
) : TypeAliasExpansionReportStrategy {
|
||||
init {
|
||||
assert(!typeAlias.expandedType.isError) { "Incorrect type alias: $typeAlias" }
|
||||
}
|
||||
|
||||
private val argumentsMapping = typeAlias.declaredTypeParameters.zip(ktTypeArguments).toMap()
|
||||
|
||||
override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, expandingType: KotlinType) {
|
||||
// No projections in type alias constructor arguments - can't happen
|
||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) {}
|
||||
override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) {
|
||||
// can't happen in non-error type
|
||||
}
|
||||
|
||||
override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {
|
||||
val descriptorForUnsubstitutedArgument = unsubstitutedArgument.constructor.declarationDescriptor
|
||||
|
||||
+16
-8
@@ -1,12 +1,20 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||
|
||||
class TColl<T, C : Collection<T>>
|
||||
class TC<T, C : Collection<T>>
|
||||
|
||||
typealias TCErr = TColl<String, <!UPPER_BOUND_VIOLATED!>Any<!>>
|
||||
typealias TCErr2 = TCErr
|
||||
typealias TCAlias<T, C> = TC<T, C>
|
||||
typealias TCAliasT<T> = TC<T, Any>
|
||||
typealias TCAliasC<C> = TC<Any, C>
|
||||
typealias TCAliasT1<T> = TCAlias<T, Any>
|
||||
typealias TCAliasC1<C> = TCAlias<Any, C>
|
||||
|
||||
fun testType1(x: TCErr) {}
|
||||
val testCtor1 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCErr()<!>
|
||||
|
||||
fun testType2(x: TCErr2) {}
|
||||
val testCtor2 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCErr2()<!>
|
||||
typealias Test1 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>
|
||||
typealias Test2 = TC<Any, Collection<Any>>
|
||||
typealias Test3 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAlias<Any, Any><!>
|
||||
typealias Test4 = TCAlias<Any, Collection<Any>>
|
||||
typealias Test5 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasT<Any><!>
|
||||
typealias Test6 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasC<Any><!>
|
||||
typealias Test7 = TCAliasC<Collection<Any>>
|
||||
typealias Test8 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasT1<Any><!>
|
||||
typealias Test9 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasC1<Any><!>
|
||||
typealias Test10 = TCAliasC1<Collection<Any>>
|
||||
|
||||
+17
-8
@@ -1,14 +1,23 @@
|
||||
package
|
||||
|
||||
public typealias TCErr = TColl<kotlin.String, kotlin.Any>
|
||||
public typealias TCErr2 = TCErr
|
||||
public val testCtor1: TColl<kotlin.String, kotlin.Any>
|
||||
public val testCtor2: TColl<kotlin.String, kotlin.Any>
|
||||
public fun testType1(/*0*/ x: TCErr [= TColl<kotlin.String, kotlin.Any>]): kotlin.Unit
|
||||
public fun testType2(/*0*/ x: TCErr2 [= TColl<kotlin.String, kotlin.Any>]): kotlin.Unit
|
||||
public typealias TCAlias</*0*/ T, /*1*/ C> = TC<T, C>
|
||||
public typealias TCAliasC</*0*/ C> = TC<kotlin.Any, C>
|
||||
public typealias TCAliasC1</*0*/ C> = TCAlias<kotlin.Any, C>
|
||||
public typealias TCAliasT</*0*/ T> = TC<T, kotlin.Any>
|
||||
public typealias TCAliasT1</*0*/ T> = TCAlias<T, kotlin.Any>
|
||||
public typealias Test1 = TC<kotlin.Any, kotlin.Any>
|
||||
public typealias Test10 = TCAliasC1<kotlin.collections.Collection<kotlin.Any>>
|
||||
public typealias Test2 = TC<kotlin.Any, kotlin.collections.Collection<kotlin.Any>>
|
||||
public typealias Test3 = TCAlias<kotlin.Any, kotlin.Any>
|
||||
public typealias Test4 = TCAlias<kotlin.Any, kotlin.collections.Collection<kotlin.Any>>
|
||||
public typealias Test5 = TCAliasT<kotlin.Any>
|
||||
public typealias Test6 = TCAliasC<kotlin.Any>
|
||||
public typealias Test7 = TCAliasC<kotlin.collections.Collection<kotlin.Any>>
|
||||
public typealias Test8 = TCAliasT1<kotlin.Any>
|
||||
public typealias Test9 = TCAliasC1<kotlin.Any>
|
||||
|
||||
public final class TColl</*0*/ T, /*1*/ C : kotlin.collections.Collection<T>> {
|
||||
public constructor TColl</*0*/ T, /*1*/ C : kotlin.collections.Collection<T>>()
|
||||
public final class TC</*0*/ T, /*1*/ C : kotlin.collections.Collection<T>> {
|
||||
public constructor TC</*0*/ T, /*1*/ C : kotlin.collections.Collection<T>>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||
|
||||
interface In<in T>
|
||||
interface Out<out T>
|
||||
|
||||
typealias InAlias<T> = In<T>
|
||||
typealias OutAlias<T> = Out<T>
|
||||
|
||||
typealias TestOutForIn<T> = In<<!CONFLICTING_PROJECTION!>out<!> T>
|
||||
typealias TestInForOut<T> = Out<<!CONFLICTING_PROJECTION!>in<!> T>
|
||||
|
||||
typealias TestOutForInWithinAlias<T> = <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>InAlias<out T><!>
|
||||
typealias TestInForOutWithinAlias<T> = <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>OutAlias<in T><!>
|
||||
|
||||
fun <T> testOutForInWithinResolvedType(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>InAlias<out T><!>) {}
|
||||
fun <T> testInForOutWithinResolvedType(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>OutAlias<in T><!>) {}
|
||||
@@ -0,0 +1,22 @@
|
||||
package
|
||||
|
||||
public typealias InAlias</*0*/ T> = In<T>
|
||||
public typealias OutAlias</*0*/ T> = Out<T>
|
||||
public typealias TestInForOut</*0*/ T> = Out<in T>
|
||||
public typealias TestInForOutWithinAlias</*0*/ T> = OutAlias<in T>
|
||||
public typealias TestOutForIn</*0*/ T> = In<out T>
|
||||
public typealias TestOutForInWithinAlias</*0*/ T> = InAlias<out T>
|
||||
public fun </*0*/ T> testInForOutWithinResolvedType(/*0*/ x: OutAlias<in T> [= Out<in T>]): kotlin.Unit
|
||||
public fun </*0*/ T> testOutForInWithinResolvedType(/*0*/ x: InAlias<out T> [= In<out T>]): kotlin.Unit
|
||||
|
||||
public interface In</*0*/ in T> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Out</*0*/ out T> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
typealias A = B
|
||||
typealias B = A
|
||||
typealias A = <!RECURSIVE_TYPEALIAS_EXPANSION!>B<!>
|
||||
typealias B = <!RECURSIVE_TYPEALIAS_EXPANSION!>A<!>
|
||||
|
||||
val x: <!RECURSIVE_TYPEALIAS_EXPANSION!>A<!> = TODO()
|
||||
@@ -19443,6 +19443,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("conflictingProjections.kt")
|
||||
public void testConflictingProjections() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/conflictingProjections.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionTypeInTypeAlias.kt")
|
||||
public void testFunctionTypeInTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/functionTypeInTypeAlias.kt");
|
||||
|
||||
Reference in New Issue
Block a user