diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 79268a0a45e..e06176aa021 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -650,6 +650,8 @@ public interface Errors { DiagnosticFactory1 UNUSED_VARIABLE = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); DiagnosticFactory1 UNUSED_PARAMETER = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); + DiagnosticFactory2 UNUSED_TYPEALIAS_PARAMETER = + DiagnosticFactory2.create(WARNING, DECLARATION_NAME); DiagnosticFactory1 ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index a74202c9366..9bad0058c87 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -428,6 +428,7 @@ public class DefaultErrorMessages { MAP.put(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION, "Conflicting projection in type alias expansion in intermediate type ''{0}''", RENDER_TYPE); MAP.put(TYPEALIAS_SHOULD_EXPAND_TO_CLASS, "Type alias expands to {0}, which is not a class, an interface, or an object", RENDER_TYPE); MAP.put(TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE, "Type alias expanded to malformed type {0}: {1}", RENDER_TYPE, STRING); + MAP.put(UNUSED_TYPEALIAS_PARAMETER, "Type alias parameter {0} is not used in the expanded type {1} and does not affect type checking", NAME, RENDER_TYPE); MAP.put(TOO_MANY_ARGUMENTS, "Too many arguments for {0}", FQ_NAMES_IN_TYPES); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 6502ab025bf..4828919470a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -35,9 +35,8 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.KotlinTypeChecker -import org.jetbrains.kotlin.types.typeUtil.contains -import org.jetbrains.kotlin.types.typeUtil.isArrayOfNothing -import org.jetbrains.kotlin.types.typeUtil.isNothing +import org.jetbrains.kotlin.types.typeUtil.* +import org.jetbrains.kotlin.utils.addToStdlib.check import java.util.* fun KtDeclaration.checkTypeReferences(trace: BindingTrace) { @@ -155,7 +154,7 @@ class DeclarationsChecker( checkTypeAliasExpansion(typeAliasDescriptor, declaration) - val expandedType = typeAliasDescriptor.expandedType // TODO refactor type alias expansion + val expandedType = typeAliasDescriptor.expandedType if (expandedType.isError) return val expandedClassifier = expandedType.constructor.declarationDescriptor @@ -167,8 +166,23 @@ class DeclarationsChecker( if (TypeUtils.contains(expandedType) { it.isArrayOfNothing()} ) { trace.report(TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE.on(typeReference, expandedType, "Array is illegal")) } + + val usedTypeAliasParameters: Set = getUsedTypeAliasParameters(expandedType, typeAliasDescriptor) + for (typeParameter in typeAliasDescriptor.declaredTypeParameters) { + if (typeParameter !in usedTypeAliasParameters) { + val source = DescriptorToSourceUtils.descriptorToDeclaration(typeParameter) as? KtTypeParameter + ?: throw AssertionError("No source element for type parameter $typeParameter of $typeAliasDescriptor") + trace.report(UNUSED_TYPEALIAS_PARAMETER.on(source, typeParameter, expandedType)) + } + } } + private fun getUsedTypeAliasParameters(type: KotlinType, typeAlias: TypeAliasDescriptor): Set = + type.constituentTypes().mapNotNullTo(HashSet()) { + val descriptor = it.constructor.declarationDescriptor as? TypeParameterDescriptor + descriptor?.check { it.containingDeclaration == typeAlias } + } + private class TypeAliasDeclarationCheckingReportStrategy( private val trace: BindingTrace, typeAliasDescriptor: TypeAliasDescriptor, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt index dba1cf04169..54037ed2d90 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt @@ -21,6 +21,8 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.containsTypeAliasParameters +import org.jetbrains.kotlin.types.typeUtil.requiresTypeAliasExpansion class TypeAliasExpander( private val reportStrategy: TypeAliasExpansionReportStrategy diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansion.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansion.kt index 1f28b291879..28cb6022b51 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansion.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansion.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.typeUtil.contains class TypeAliasExpansion private constructor( val parent: TypeAliasExpansion?, @@ -56,23 +57,3 @@ class TypeAliasExpansion private constructor( create(null, typeAliasDescriptor, emptyList()) } } - -fun KotlinType.containsTypeAliasParameters(): Boolean = - TypeUtils.contains(this) { - it.constructor.declarationDescriptor?.isTypeAliasParameter() ?: false - } - -fun KotlinType.containsTypeAliases(): Boolean = - TypeUtils.contains(this) { - it.constructor.declarationDescriptor is TypeAliasDescriptor - } - -fun ClassifierDescriptor.isTypeAliasParameter(): Boolean = - this is TypeParameterDescriptor && containingDeclaration is TypeAliasDescriptor - -fun KotlinType.requiresTypeAliasExpansion(): Boolean = - TypeUtils.contains(this) { - it.constructor.declarationDescriptor?.let { - it is TypeAliasDescriptor || it is TypeParameterDescriptor - } - } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index 84f09123f33..d11b4e6e6d5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -35,8 +35,6 @@ import org.jetbrains.kotlin.psi.debugText.getDebugText import org.jetbrains.kotlin.resolve.PossiblyBareType.type import org.jetbrains.kotlin.resolve.bindingContextUtil.recordScope import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors -import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil -import org.jetbrains.kotlin.resolve.lazy.LazyEntity import org.jetbrains.kotlin.resolve.scopes.LazyScopeAdapter import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -44,10 +42,10 @@ import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier import org.jetbrains.kotlin.resolve.source.toSourceElement import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.StorageManager -import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.Variance.* -import org.jetbrains.kotlin.types.typeUtil.contains +import org.jetbrains.kotlin.types.typeUtil.containsTypeAliasParameters +import org.jetbrains.kotlin.types.typeUtil.containsTypeAliases import org.jetbrains.kotlin.types.typeUtil.isArrayOfNothing class TypeResolver( diff --git a/compiler/testData/diagnostics/tests/typealias/genericTypeAliasObject.kt b/compiler/testData/diagnostics/tests/typealias/genericTypeAliasObject.kt index fe4d61cd67c..507aa9d889b 100644 --- a/compiler/testData/diagnostics/tests/typealias/genericTypeAliasObject.kt +++ b/compiler/testData/diagnostics/tests/typealias/genericTypeAliasObject.kt @@ -3,7 +3,7 @@ object AnObject { fun foo() = "OK" } -typealias GenericTestObject = AnObject +typealias GenericTestObject<T> = AnObject val test11: AnObject = GenericTestObject val test12: GenericTestObject<*> = GenericTestObject diff --git a/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt b/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt index cf1d2a3191f..a4aabeeb409 100644 --- a/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt +++ b/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt @@ -1,3 +1,5 @@ +// !DIAGNOSTICS: -UNUSED_TYPEALIAS_PARAMETER + typealias WithVariance<in X, out Y> = Int typealias WithBounds1T> = Int typealias WithBounds2Y, Y : X> = Int diff --git a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt index 1b355a97f89..92fa20a434e 100644 --- a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt +++ b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt @@ -5,16 +5,16 @@ class Inv typealias In1 = In typealias In2 = In<in T> typealias In3 = In<out T> -typealias In4 = In<*> +typealias In4<T> = In<*> typealias Out1 = Out typealias Out2 = Out<in T> typealias Out3 = Out<out T> -typealias Out4 = Out<*> +typealias Out4<T> = Out<*> typealias Inv1 = Inv typealias Inv2 = Inv typealias Inv3 = Inv -typealias Inv4 = Inv<*> +typealias Inv4<T> = Inv<*> val inv1: Inv1 = Inv() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.kt index 3e34b052738..c61c176063c 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.kt @@ -1,6 +1,6 @@ typealias ToTypeParam1 = T typealias ToTypeParam2 = ToTypeParam1 -typealias ToTypeParam3 = ToTypeParam2 +typealias ToTypeParam3T2> = ToTypeParam2 typealias ToTypeParam4 = ToTypeParam1 typealias ToFun1 = () -> Unit @@ -9,6 +9,6 @@ typealias ToFun2 = (T) -> Unit class Outer { typealias ToTypeParam1 = T typealias ToTypeParam2 = ToTypeParam1 - typealias ToTypeParam3 = ToTypeParam2 + typealias ToTypeParam3T2> = ToTypeParam2 typealias ToTypeParam4 = ToTypeParam1 } diff --git a/compiler/testData/diagnostics/tests/typealias/unusedTypeAliasParameter.kt b/compiler/testData/diagnostics/tests/typealias/unusedTypeAliasParameter.kt new file mode 100644 index 00000000000..2d11992bd01 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/unusedTypeAliasParameter.kt @@ -0,0 +1,2 @@ +typealias TestX> = List +typealias Test2X> = Test diff --git a/compiler/testData/diagnostics/tests/typealias/unusedTypeAliasParameter.txt b/compiler/testData/diagnostics/tests/typealias/unusedTypeAliasParameter.txt new file mode 100644 index 00000000000..c329e92805f --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/unusedTypeAliasParameter.txt @@ -0,0 +1,4 @@ +package + +public typealias Test = kotlin.collections.List +public typealias Test2 = Test diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index b8505575af5..7bdaee9fa81 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -19647,6 +19647,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("unusedTypeAliasParameter.kt") + public void testUnusedTypeAliasParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/unusedTypeAliasParameter.kt"); + doTest(fileName); + } + @TestMetadata("wrongNumberOfArgumentsInTypeAliasConstructor.kt") public void testWrongNumberOfArgumentsInTypeAliasConstructor() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index 707b6096fbb..c11dc8fed3e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -17,9 +17,7 @@ package org.jetbrains.kotlin.types.typeUtil import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.inference.isCaptured @@ -128,6 +126,9 @@ fun constituentTypes(types: Collection): Collection { return result } +fun KotlinType.constituentTypes(): Collection = + constituentTypes(listOf(this)) + private fun constituentTypes(result: MutableSet, types: Collection) { result.addAll(types) for (type in types) { @@ -135,7 +136,7 @@ private fun constituentTypes(result: MutableSet, types: Collection