diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index ecbd2080908..4aa4bc17ad4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -118,7 +118,7 @@ public interface Errors { DiagnosticFactory0 GENERIC_THROWABLE_SUBCLASS = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 UNSUPPORTED_TYPEALIAS = DiagnosticFactory0.create(ERROR); - DiagnosticFactory1 RECURSIVE_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 RECURSIVE_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR); DiagnosticFactory3 UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION = DiagnosticFactory3.create(ERROR); DiagnosticFactory1 CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 4ddcd7971ff..6dea0a8c3ea 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -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) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt index a52e32bfa55..5e01e42d82d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt @@ -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 } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt index 26aa83cc0a8..99325cb491a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt @@ -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) {} } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index 5a38c558c82..67344716e15 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -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)) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index b9174bd3ca2..62eade94064 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -595,16 +595,23 @@ class CandidateResolver( ktTypeArguments: List, 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 diff --git a/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasRHS.kt b/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasRHS.kt index 003d367dc6a..d8f638d808d 100644 --- a/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasRHS.kt +++ b/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasRHS.kt @@ -1,12 +1,20 @@ // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -class TColl> +class TC> -typealias TCErr = TCollAny> -typealias TCErr2 = TCErr +typealias TCAlias = TC +typealias TCAliasT = TC +typealias TCAliasC = TC +typealias TCAliasT1 = TCAlias +typealias TCAliasC1 = TCAlias -fun testType1(x: TCErr) {} -val testCtor1 = TCErr() - -fun testType2(x: TCErr2) {} -val testCtor2 = TCErr2() +typealias Test1 = TCAny> +typealias Test2 = TC> +typealias Test3 = TCAlias +typealias Test4 = TCAlias> +typealias Test5 = TCAliasT +typealias Test6 = TCAliasC +typealias Test7 = TCAliasC> +typealias Test8 = TCAliasT1 +typealias Test9 = TCAliasC1 +typealias Test10 = TCAliasC1> diff --git a/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasRHS.txt b/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasRHS.txt index f0f04412d92..abde87661f8 100644 --- a/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasRHS.txt +++ b/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasRHS.txt @@ -1,14 +1,23 @@ package -public typealias TCErr = TColl -public typealias TCErr2 = TCErr -public val testCtor1: TColl -public val testCtor2: TColl -public fun testType1(/*0*/ x: TCErr [= TColl]): kotlin.Unit -public fun testType2(/*0*/ x: TCErr2 [= TColl]): kotlin.Unit +public typealias TCAlias = TC +public typealias TCAliasC = TC +public typealias TCAliasC1 = TCAlias +public typealias TCAliasT = TC +public typealias TCAliasT1 = TCAlias +public typealias Test1 = TC +public typealias Test10 = TCAliasC1> +public typealias Test2 = TC> +public typealias Test3 = TCAlias +public typealias Test4 = TCAlias> +public typealias Test5 = TCAliasT +public typealias Test6 = TCAliasC +public typealias Test7 = TCAliasC> +public typealias Test8 = TCAliasT1 +public typealias Test9 = TCAliasC1 -public final class TColl> { - public constructor TColl>() +public final class TC> { + public constructor TC>() 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 diff --git a/compiler/testData/diagnostics/tests/typealias/conflictingProjections.kt b/compiler/testData/diagnostics/tests/typealias/conflictingProjections.kt new file mode 100644 index 00000000000..c744a0af056 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/conflictingProjections.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER + +interface In +interface Out + +typealias InAlias = In +typealias OutAlias = Out + +typealias TestOutForIn = In<out T> +typealias TestInForOut = Out<in T> + +typealias TestOutForInWithinAlias = InAlias +typealias TestInForOutWithinAlias = OutAlias + +fun testOutForInWithinResolvedType(x: InAlias) {} +fun testInForOutWithinResolvedType(x: OutAlias) {} diff --git a/compiler/testData/diagnostics/tests/typealias/conflictingProjections.txt b/compiler/testData/diagnostics/tests/typealias/conflictingProjections.txt new file mode 100644 index 00000000000..646157b019b --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/conflictingProjections.txt @@ -0,0 +1,22 @@ +package + +public typealias InAlias = In +public typealias OutAlias = Out +public typealias TestInForOut = Out +public typealias TestInForOutWithinAlias = OutAlias +public typealias TestOutForIn = In +public typealias TestOutForInWithinAlias = InAlias +public fun testInForOutWithinResolvedType(/*0*/ x: OutAlias [= Out]): kotlin.Unit +public fun testOutForInWithinResolvedType(/*0*/ x: InAlias [= In]): kotlin.Unit + +public interface In { + 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 { + 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 +} diff --git a/compiler/testData/diagnostics/tests/typealias/recursive.kt b/compiler/testData/diagnostics/tests/typealias/recursive.kt index d64150b2e15..97ea09f10ee 100644 --- a/compiler/testData/diagnostics/tests/typealias/recursive.kt +++ b/compiler/testData/diagnostics/tests/typealias/recursive.kt @@ -1,4 +1,4 @@ -typealias A = B -typealias B = A +typealias A = B +typealias B = A val x: A = TODO() \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 5610acd614d..b9e7b027aca 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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");