diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index c75be75ac89..ea3fe2767ab 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -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 = java.util.HashMap // can be used as bare type + * typealias MyList = List // can be used as bare type + * typealias StarMap = Map // can be used as bare type + * typealias MyMap = Map // CAN NOT be used as bare type: type parameter 'T' is used twice + * typealias StringMap = Map // 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() + 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 } /** diff --git a/compiler/testData/codegen/box/typealias/typeAliasAsBareType.kt b/compiler/testData/codegen/box/typealias/typeAliasAsBareType.kt new file mode 100644 index 00000000000..eed82fc0045 --- /dev/null +++ b/compiler/testData/codegen/box/typealias/typeAliasAsBareType.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +typealias L = List + +fun box(): String { + val test: Collection = 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" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.kt new file mode 100644 index 00000000000..a3bfa09e3d9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.kt @@ -0,0 +1,33 @@ +typealias L = List +typealias NL = List? +typealias LStar<T> = List<*> +typealias MyList<T, X> = List + +fun testL1(x: Collection) = x is L +fun testL2(x: Collection): List = x as L +fun testL3(x: Collection?): List? = x as L? +fun testL4(x: Collection?): List? = x as? L + +fun testNL1(x: Collection?): Boolean = x is NL +fun testNL2(x: Collection?): List? = x as NL +fun testNL3(x: Collection?): List? = x as NL? + +fun testLStar(x: Collection): List = x as LStar +fun testMyList(x: Collection): List = x as MyList + +typealias MMTT = MutableMap +typealias Dictionary = MutableMap +typealias WriteableMap = MutableMap +typealias ReadableList = MutableList + +fun testWrong1(x: Map) = x is MMTT +fun testWrong2(x: Map) = x is Dictionary +fun testWrong3(x: Map) = x is WriteableMap +fun testWrong4(x: List) = x is ReadableList + +fun testLocal(x: Any) { + class C + typealias CA = C + if (x is C) {} + if (x is CA) {} +} diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.txt b/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.txt new file mode 100644 index 00000000000..03e0005f515 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.txt @@ -0,0 +1,24 @@ +package + +public fun testL1(/*0*/ x: kotlin.collections.Collection): kotlin.Boolean +public fun testL2(/*0*/ x: kotlin.collections.Collection): kotlin.collections.List +public fun testL3(/*0*/ x: kotlin.collections.Collection?): kotlin.collections.List? +public fun testL4(/*0*/ x: kotlin.collections.Collection?): kotlin.collections.List? +public fun testLStar(/*0*/ x: kotlin.collections.Collection): kotlin.collections.List +public fun testLocal(/*0*/ x: kotlin.Any): kotlin.Unit +public fun testMyList(/*0*/ x: kotlin.collections.Collection): kotlin.collections.List +public fun testNL1(/*0*/ x: kotlin.collections.Collection?): kotlin.Boolean +public fun testNL2(/*0*/ x: kotlin.collections.Collection?): kotlin.collections.List? +public fun testNL3(/*0*/ x: kotlin.collections.Collection?): kotlin.collections.List? +public fun testWrong1(/*0*/ x: kotlin.collections.Map): kotlin.Boolean +public fun testWrong2(/*0*/ x: kotlin.collections.Map): kotlin.Boolean +public fun testWrong3(/*0*/ x: kotlin.collections.Map): kotlin.Boolean +public fun testWrong4(/*0*/ x: kotlin.collections.List): kotlin.Boolean +public typealias Dictionary = kotlin.collections.MutableMap +public typealias L = kotlin.collections.List +public typealias LStar = kotlin.collections.List<*> +public typealias MMTT = kotlin.collections.MutableMap +public typealias MyList = kotlin.collections.List +public typealias NL = kotlin.collections.List? +public typealias ReadableList = kotlin.collections.MutableList +public typealias WriteableMap = kotlin.collections.MutableMap diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 9d76fe37fb2..e28de189b5a 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 44382c82ff9..9c6d1ecec8b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 9acf54763e7..78a5ee86205 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index f3d738aa2dc..86d6d28eb17 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -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");