Support type aliases as bare types after 'is/as'.
This commit is contained in:
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.debugTypeInfo
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
||||
import org.jetbrains.kotlin.psi.debugText.getDebugText
|
||||
import org.jetbrains.kotlin.resolve.PossiblyBareType.bare
|
||||
import org.jetbrains.kotlin.resolve.PossiblyBareType.type
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.recordScope
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors
|
||||
@@ -467,6 +468,13 @@ class TypeResolver(
|
||||
|
||||
val parameters = typeConstructor.parameters
|
||||
|
||||
if (c.allowBareTypes && projectionFromAllQualifierParts.isEmpty() && isPossibleToSpecifyTypeArgumentsFor(descriptor)) {
|
||||
val classDescriptor = descriptor.classDescriptor
|
||||
if (classDescriptor != null && canBeUsedAsBareType(descriptor)) {
|
||||
return bare(descriptor.classDescriptor!!.typeConstructor, TypeUtils.isNullableType(descriptor.expandedType))
|
||||
}
|
||||
}
|
||||
|
||||
val typeAliasQualifierPart =
|
||||
qualifierResolutionResult.qualifierParts.lastOrNull()
|
||||
?: return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor)
|
||||
@@ -502,6 +510,44 @@ class TypeResolver(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type alias can be used as bare type (after is/as, e.g., 'x is List')
|
||||
* iff all type arguments of the corresponding expanded type are either star projections
|
||||
* or type parameters of the given type alias in invariant projection,
|
||||
* and each of the type parameters is mentioned no more than once.
|
||||
*
|
||||
* E.g.:
|
||||
* ```
|
||||
* typealias HashMap<K, V> = java.util.HashMap<K, V> // can be used as bare type
|
||||
* typealias MyList<T, X> = List<X> // can be used as bare type
|
||||
* typealias StarMap<T> = Map<T, *> // can be used as bare type
|
||||
* typealias MyMap<T> = Map<T, T> // CAN NOT be used as bare type: type parameter 'T' is used twice
|
||||
* typealias StringMap<T> = Map<String, T> // CAN NOT be used as bare type: type argument 'String' is not a type parameter
|
||||
* ```
|
||||
*/
|
||||
private fun canBeUsedAsBareType(descriptor: TypeAliasDescriptor): Boolean {
|
||||
val expandedType = descriptor.expandedType
|
||||
if (expandedType.isError) return false
|
||||
|
||||
val classDescriptor = descriptor.classDescriptor ?: return false
|
||||
if (!isPossibleToSpecifyTypeArgumentsFor(classDescriptor)) return false
|
||||
|
||||
val usedTypeParameters = linkedSetOf<TypeParameterDescriptor>()
|
||||
for (argument in expandedType.arguments) {
|
||||
if (argument.isStarProjection) continue
|
||||
|
||||
if (argument.projectionKind != INVARIANT) return false
|
||||
|
||||
val argumentTypeDescriptor = argument.type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false
|
||||
if (argumentTypeDescriptor.containingDeclaration != descriptor) return false
|
||||
if (usedTypeParameters.contains(argumentTypeDescriptor)) return false
|
||||
|
||||
usedTypeParameters.add(argumentTypeDescriptor)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private class TracingTypeAliasExpansionReportStrategy(
|
||||
val trace: BindingTrace,
|
||||
val type: KtElement?,
|
||||
@@ -578,7 +624,7 @@ class TypeResolver(
|
||||
// First parameter relates to the innermost declaration
|
||||
// If it's declared in function there
|
||||
val firstTypeParameter = classifierDescriptor.typeConstructor.parameters.firstOrNull() ?: return false
|
||||
return firstTypeParameter.original.containingDeclaration is ClassDescriptor
|
||||
return firstTypeParameter.original.containingDeclaration is ClassifierDescriptorWithTypeParameters
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
typealias L<T> = List<T>
|
||||
|
||||
fun box(): String {
|
||||
val test: Collection<Int> = listOf(1, 2, 3)
|
||||
if (test !is L) return "test !is L"
|
||||
val test2 = test as L
|
||||
if (test.toList() != test2) return "test.toList() != test2"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
typealias L<T> = List<T>
|
||||
typealias NL<T> = List<T>?
|
||||
typealias LStar<<!UNUSED_TYPEALIAS_PARAMETER!>T<!>> = List<*>
|
||||
typealias MyList<<!UNUSED_TYPEALIAS_PARAMETER!>T<!>, X> = List<X>
|
||||
|
||||
fun testL1(x: Collection<Any>) = x is L
|
||||
fun testL2(x: Collection<Int>): List<Int> = x as L
|
||||
fun testL3(x: Collection<Int>?): List<Int>? = x as L?
|
||||
fun testL4(x: Collection<Int>?): List<Int>? = x as? L
|
||||
|
||||
fun testNL1(x: Collection<Int>?): Boolean = x is NL
|
||||
fun testNL2(x: Collection<Int>?): List<Int>? = x as NL
|
||||
fun testNL3(x: Collection<Int>?): List<Int>? = x as NL<!REDUNDANT_NULLABLE!>?<!>
|
||||
|
||||
fun testLStar(x: Collection<Int>): List<Int> = x as LStar
|
||||
fun testMyList(x: Collection<Int>): List<Int> = x as MyList
|
||||
|
||||
typealias MMTT<T> = MutableMap<T, T>
|
||||
typealias Dictionary<T> = MutableMap<String, T>
|
||||
typealias WriteableMap<K, V> = MutableMap<in K, V>
|
||||
typealias ReadableList<T> = MutableList<out T>
|
||||
|
||||
fun testWrong1(x: Map<Any, Any>) = x is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>MMTT<!>
|
||||
fun testWrong2(x: Map<Any, Any>) = x is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Dictionary<!>
|
||||
fun testWrong3(x: Map<Any, Any>) = x is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>WriteableMap<!>
|
||||
fun testWrong4(x: List<Any>) = x is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>ReadableList<!>
|
||||
|
||||
fun <T> testLocal(x: Any) {
|
||||
class C
|
||||
typealias CA = C
|
||||
if (x is <!CANNOT_CHECK_FOR_ERASED!>C<!>) {}
|
||||
if (x is <!CANNOT_CHECK_FOR_ERASED!>CA<!>) {}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun testL1(/*0*/ x: kotlin.collections.Collection<kotlin.Any>): kotlin.Boolean
|
||||
public fun testL2(/*0*/ x: kotlin.collections.Collection<kotlin.Int>): kotlin.collections.List<kotlin.Int>
|
||||
public fun testL3(/*0*/ x: kotlin.collections.Collection<kotlin.Int>?): kotlin.collections.List<kotlin.Int>?
|
||||
public fun testL4(/*0*/ x: kotlin.collections.Collection<kotlin.Int>?): kotlin.collections.List<kotlin.Int>?
|
||||
public fun testLStar(/*0*/ x: kotlin.collections.Collection<kotlin.Int>): kotlin.collections.List<kotlin.Int>
|
||||
public fun </*0*/ T> testLocal(/*0*/ x: kotlin.Any): kotlin.Unit
|
||||
public fun testMyList(/*0*/ x: kotlin.collections.Collection<kotlin.Int>): kotlin.collections.List<kotlin.Int>
|
||||
public fun testNL1(/*0*/ x: kotlin.collections.Collection<kotlin.Int>?): kotlin.Boolean
|
||||
public fun testNL2(/*0*/ x: kotlin.collections.Collection<kotlin.Int>?): kotlin.collections.List<kotlin.Int>?
|
||||
public fun testNL3(/*0*/ x: kotlin.collections.Collection<kotlin.Int>?): kotlin.collections.List<kotlin.Int>?
|
||||
public fun testWrong1(/*0*/ x: kotlin.collections.Map<kotlin.Any, kotlin.Any>): kotlin.Boolean
|
||||
public fun testWrong2(/*0*/ x: kotlin.collections.Map<kotlin.Any, kotlin.Any>): kotlin.Boolean
|
||||
public fun testWrong3(/*0*/ x: kotlin.collections.Map<kotlin.Any, kotlin.Any>): kotlin.Boolean
|
||||
public fun testWrong4(/*0*/ x: kotlin.collections.List<kotlin.Any>): kotlin.Boolean
|
||||
public typealias Dictionary</*0*/ T> = kotlin.collections.MutableMap<kotlin.String, T>
|
||||
public typealias L</*0*/ T> = kotlin.collections.List<T>
|
||||
public typealias LStar</*0*/ T> = kotlin.collections.List<*>
|
||||
public typealias MMTT</*0*/ T> = kotlin.collections.MutableMap<T, T>
|
||||
public typealias MyList</*0*/ T, /*1*/ X> = kotlin.collections.List<X>
|
||||
public typealias NL</*0*/ T> = kotlin.collections.List<T>?
|
||||
public typealias ReadableList</*0*/ T> = kotlin.collections.MutableList<out T>
|
||||
public typealias WriteableMap</*0*/ K, /*1*/ V> = kotlin.collections.MutableMap<in K, V>
|
||||
+6
@@ -16049,6 +16049,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasAsBareType.kt")
|
||||
public void testTypeAliasAsBareType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/typealias/typeAliasAsBareType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasCompanion.kt")
|
||||
public void testTypeAliasCompanion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/typealias/typeAliasCompanion.kt");
|
||||
|
||||
@@ -21022,6 +21022,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasAsBareType.kt")
|
||||
public void testTypeAliasAsBareType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasAsQualifier.kt")
|
||||
public void testTypeAliasAsQualifier() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasAsQualifier.kt");
|
||||
|
||||
@@ -16049,6 +16049,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasAsBareType.kt")
|
||||
public void testTypeAliasAsBareType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/typealias/typeAliasAsBareType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasCompanion.kt")
|
||||
public void testTypeAliasCompanion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/typealias/typeAliasCompanion.kt");
|
||||
|
||||
@@ -20829,6 +20829,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasAsBareType.kt")
|
||||
public void testTypeAliasAsBareType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/typealias/typeAliasAsBareType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasCompanion.kt")
|
||||
public void testTypeAliasCompanion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/typealias/typeAliasCompanion.kt");
|
||||
|
||||
Reference in New Issue
Block a user