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 21b85ccc2a8..afd155c0b03 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -416,7 +416,7 @@ public class DefaultErrorMessages { MAP.put(TYPE_MISMATCH_IN_RANGE, "Type mismatch: incompatible types of range and element checked in it"); MAP.put(CYCLIC_INHERITANCE_HIERARCHY, "There's a cycle in the inheritance hierarchy for this type"); - MAP.put(CYCLIC_GENERIC_UPPER_BOUND, "Type parameter has itself as an upper bound"); + MAP.put(CYCLIC_GENERIC_UPPER_BOUND, "Type parameter has cyclic upper bounds"); MAP.put(MANY_CLASSES_IN_SUPERTYPE_LIST, "Only one class may appear in a supertype list"); MAP.put(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE, "Only classes and interfaces may serve as supertypes"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 3ecd50e64b2..6d0dc576684 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -23,6 +23,7 @@ import com.intellij.psi.PsiElement; import kotlin.CollectionsKt; import kotlin.SetsKt; import kotlin.jvm.functions.Function0; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; @@ -410,9 +411,9 @@ public class DescriptorResolver { DeclarationDescriptor containingDescriptor, LexicalWritableScope extensibleScope, LexicalScope scopeForAnnotationsResolve, - KtTypeParameter typeParameter, + final KtTypeParameter typeParameter, int index, - BindingTrace trace + final BindingTrace trace ) { if (typeParameter.getVariance() != Variance.INVARIANT) { assert !(containingDescriptor instanceof ClassifierDescriptor) : "This method is intended for functions/properties"; @@ -429,8 +430,16 @@ public class DescriptorResolver { typeParameter.getVariance(), KtPsiUtil.safeName(typeParameter.getName()), index, - KotlinSourceElementKt.toSourceElement(typeParameter) - ); + KotlinSourceElementKt.toSourceElement(typeParameter), + new Function1() { + @Override + public Void invoke(KotlinType type) { + trace.report(Errors.CYCLIC_GENERIC_UPPER_BOUND.on(typeParameter)); + return null; + } + }, + supertypeLoopsResolver + ); trace.record(BindingContext.TYPE_PARAMETER, typeParameter, typeParameterDescriptor); extensibleScope.addClassifierDescriptor(typeParameterDescriptor); return typeParameterDescriptor; @@ -461,20 +470,6 @@ public class DescriptorResolver { } } - public KotlinType resolveTypeParameterExtendsBound( - @NotNull TypeParameterDescriptor typeParameterDescriptor, - @NotNull KtTypeReference extendsBound, - LexicalScope scope, - BindingTrace trace - ) { - KotlinType type = typeResolver.resolveType(scope, extendsBound, trace, false); - if (type.getConstructor().equals(typeParameterDescriptor.getTypeConstructor())) { - trace.report(Errors.CYCLIC_GENERIC_UPPER_BOUND.on(extendsBound)); - type = ErrorUtils.createErrorType("Cyclic upper bound: " + type); - } - return type; - } - public void resolveGenericBounds( @NotNull KtTypeParameterListOwner declaration, @NotNull DeclarationDescriptor descriptor, @@ -494,7 +489,7 @@ public class DescriptorResolver { KtTypeReference extendsBound = jetTypeParameter.getExtendsBound(); if (extendsBound != null) { - KotlinType type = resolveTypeParameterExtendsBound(typeParameterDescriptor, extendsBound, scope, trace); + KotlinType type = typeResolver.resolveType(scope, extendsBound, trace, false); typeParameterDescriptor.addUpperBound(type); deferredUpperBoundCheckerTasks.add(new UpperBoundCheckerTask(extendsBound, type)); } @@ -523,9 +518,10 @@ public class DescriptorResolver { for (TypeParameterDescriptorImpl parameter : parameters) { parameter.addDefaultUpperBound(); - parameter.setInitialized(); + } + for (TypeParameterDescriptorImpl parameter : parameters) { checkConflictingUpperBounds(trace, parameter, typeParameters.get(parameter.getIndex())); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyTypeParameterDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyTypeParameterDescriptor.java index c95d2a5bc87..d5f3c50910d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyTypeParameterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyTypeParameterDescriptor.java @@ -18,7 +18,9 @@ package org.jetbrains.kotlin.resolve.lazy.descriptors; import kotlin.CollectionsKt; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker; import org.jetbrains.kotlin.descriptors.impl.AbstractLazyTypeParameterDescriptor; +import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; @@ -58,6 +60,22 @@ public class LazyTypeParameterDescriptor extends AbstractLazyTypeParameterDescri this.c.getTrace().record(BindingContext.TYPE_PARAMETER, typeParameter, this); } + @NotNull + @Override + protected SupertypeLoopChecker getSupertypeLoopChecker() { + return c.getSupertypeLoopChecker(); + } + + @Override + protected void reportCycleError(@NotNull KotlinType type) { + for (KtTypeReference typeReference : getAllUpperBounds()) { + if (resolveBoundType(typeReference).getConstructor().equals(type.getConstructor())) { + c.getTrace().report(Errors.CYCLIC_GENERIC_UPPER_BOUND.on(typeReference)); + return; + } + } + } + @NotNull @Override protected List resolveUpperBounds() { diff --git a/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.kt b/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.kt new file mode 100644 index 00000000000..15adca210d5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.kt @@ -0,0 +1,7 @@ +fun <T : F?, F : T?> foo1() {} + +fun F : E, E : F?> foo2() {} + +fun <T, F> foo3() where T : F?, F : T {} + +fun F, E> foo4() where T : F?, F : E, E : F? {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.txt b/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.txt new file mode 100644 index 00000000000..918ffd247d3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.txt @@ -0,0 +1,6 @@ +package + +public fun foo1(): kotlin.Unit +public fun foo2(): kotlin.Unit +public fun foo3(): kotlin.Unit +public fun foo4(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.kt b/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.kt new file mode 100644 index 00000000000..3e4a0209ee1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.kt @@ -0,0 +1,7 @@ +class A1F?, F : T?> + +class A2E, E : F?> + +class A3 where T : F?, F : T? + +class A4 where T : F?, F : E, E : F \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.txt b/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.txt new file mode 100644 index 00000000000..a4712d3ca3b --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.txt @@ -0,0 +1,29 @@ +package + +public final class A1 { + public constructor A1() + 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 final class A2 { + public constructor A2() + 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 final class A3 { + public constructor A3() + 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 final class A4 { + public constructor A4() + 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/j+k/recursiveRawUpperBound2.kt b/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound2.kt new file mode 100644 index 00000000000..dfc3e1205f9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound2.kt @@ -0,0 +1,8 @@ +// FILE: XYZ.java +public interface XYZ { + XYZ foo() {} +} + +// FILE: main.kt + +fun main(xyz: XYZ<*>) = xyz.foo() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound2.txt b/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound2.txt new file mode 100644 index 00000000000..647d7af530d --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound2.txt @@ -0,0 +1,11 @@ +package + +public /*synthesized*/ fun XYZ(/*0*/ function: () -> XYZ<(raw) [ERROR : Cyclic upper bounds]>!): XYZ +public fun main(/*0*/ xyz: XYZ<*>): XYZ<(raw) [ERROR : Cyclic upper bounds]>! + +public interface XYZ { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): XYZ<(raw) [ERROR : Cyclic upper bounds]>! + 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/j+k/recursiveRawUpperBound3.kt b/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound3.kt new file mode 100644 index 00000000000..282814ecf53 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound3.kt @@ -0,0 +1,8 @@ +// FILE: XYZ.java +public interface XYZ { + XYZ foo() {} +} + +// FILE: main.kt + +fun main(xyz: XYZ<*, *, *>) = xyz.foo() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound3.txt b/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound3.txt new file mode 100644 index 00000000000..c9c34daf7f7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound3.txt @@ -0,0 +1,11 @@ +package + +public /*synthesized*/ fun XYZ(/*0*/ function: () -> XYZ<(raw) [ERROR : Cyclic upper bounds], (raw) [ERROR : Cyclic upper bounds], (raw) [ERROR : Cyclic upper bounds]>!): XYZ +public fun main(/*0*/ xyz: XYZ<*, *, *>): XYZ<(raw) [ERROR : Cyclic upper bounds], (raw) [ERROR : Cyclic upper bounds], (raw) [ERROR : Cyclic upper bounds]>! + +public interface XYZ { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): XYZ<(raw) [ERROR : Cyclic upper bounds], (raw) [ERROR : Cyclic upper bounds], (raw) [ERROR : Cyclic upper bounds]>! + 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/regressions/itselfAsUpperBound.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.kt index fd37f7ee7e0..6d80f09022d 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.kt @@ -1,3 +1,3 @@ // !DIAGNOSTICS: -MUST_BE_INITIALIZED -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER -fun T?> foo() {} -val T?> prop +fun <T: T?> foo() {} +val <T: T?> prop \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.txt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.txt index bb73761bbbb..a257a5a2084 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.txt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.txt @@ -1,4 +1,4 @@ package -public val prop: [ERROR : No type, no body] -public fun foo(): kotlin.Unit +public val prop: [ERROR : No type, no body] +public fun foo(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.txt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.txt index b8dc31c5b70..aae2a425860 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.txt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.txt @@ -1,7 +1,7 @@ package -public final class MyClass { - public constructor MyClass() +public final class MyClass { + public constructor MyClass() 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/regressions/itselfAsUpperBoundInClassNotNull.txt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.txt index 4b26ed7d387..aae2a425860 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.txt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.txt @@ -1,7 +1,7 @@ package -public final class MyClass { - public constructor MyClass() +public final class MyClass { + public constructor MyClass() 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/regressions/itselfAsUpperBoundLocal.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundLocal.kt index 35af733335a..63ff6933834 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundLocal.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundLocal.kt @@ -1,4 +1,4 @@ fun bar() { - fun T?> foo() {} + fun <T: T?> foo() {} foo() } diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.kt index bd0f7d0094e..4ab350e74cc 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -MUST_BE_INITIALIZED_OR_BE_ABSTRACT -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER class My { - fun T?> foo() {} - val T?> prop: T + fun <T: T?> foo() {} + val <T: T?> prop: T } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.txt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.txt index 61d40fcf358..97459d03c6d 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.txt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.txt @@ -2,9 +2,9 @@ package public final class My { public constructor My() - public final val prop: [ERROR : ?] + public final val prop: [ERROR : ?] public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public final fun foo(): kotlin.Unit + public final fun foo(): kotlin.Unit 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/regressions/itselfAsUpperBoundNotNull.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.kt index d7cb5e2afe3..3fe62f6097a 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.kt @@ -1,3 +1,3 @@ // !DIAGNOSTICS: -MUST_BE_INITIALIZED -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER -fun T> foo() {} -val T?> prop: T +fun <T: T> foo() {} +val <T: T?> prop: T \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.txt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.txt index 2ab1b63c966..1648ff0b222 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.txt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.txt @@ -1,4 +1,4 @@ package -public val prop: [ERROR : ?] -public fun foo(): kotlin.Unit +public val prop: [ERROR : ?] +public fun foo(): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 5dc718ea9f5..5d4cb816692 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -6618,6 +6618,27 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("compiler/testData/diagnostics/tests/generics/cyclicBounds") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CyclicBounds extends AbstractJetDiagnosticsTest { + public void testAllFilesPresentInCyclicBounds() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/generics/cyclicBounds"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("functions.kt") + public void testFunctions() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.kt"); + doTest(fileName); + } + + @TestMetadata("inClass.kt") + public void testInClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/generics/nullability") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -9252,6 +9273,18 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("recursiveRawUpperBound2.kt") + public void testRecursiveRawUpperBound2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound2.kt"); + doTest(fileName); + } + + @TestMetadata("recursiveRawUpperBound3.kt") + public void testRecursiveRawUpperBound3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/recursiveRawUpperBound3.kt"); + doTest(fileName); + } + @TestMetadata("samInConstructorWithGenerics.kt") public void testSamInConstructorWithGenerics() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/samInConstructorWithGenerics.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaTypeParameterDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaTypeParameterDescriptor.kt index d4cf51e870b..571cc9a0a29 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaTypeParameterDescriptor.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaTypeParameterDescriptor.kt @@ -54,4 +54,10 @@ class LazyJavaTypeParameterDescriptor( c.typeResolver.transformJavaType(it, TypeUsage.UPPER_BOUND.toAttributes(upperBoundForTypeParameter = this)) } } + + override fun getSupertypeLoopChecker() = c.components.supertypeLoopChecker + + override fun reportCycleError(type: KotlinType) { + // Do nothing + } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeParameterDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeParameterDescriptor.java index d74de66daf3..613fa90dfdc 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeParameterDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeParameterDescriptor.java @@ -16,13 +16,11 @@ package org.jetbrains.kotlin.descriptors.impl; +import kotlin.Unit; import kotlin.jvm.functions.Function0; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.ReadOnly; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorVisitor; -import org.jetbrains.kotlin.descriptors.SourceElement; -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.scopes.ChainedScope; @@ -96,14 +94,57 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip ); } }); - this.upperBounds = storageManager.createRecursionTolerantLazyValue(new Function0>() { - @Override - public List invoke() { - return resolveUpperBounds(); - } - }, FALLBACK_UPPER_BOUNDS_ON_RECURSION); + this.upperBounds = storageManager.createLazyValueWithPostCompute( + new Function0>() { + @Override + public List invoke() { + return resolveUpperBounds(); + } + }, + new Function1>() { + @Override + public List invoke(Boolean aBoolean) { + return FALLBACK_UPPER_BOUNDS_ON_RECURSION; + } + }, + new Function1, Unit>() { + @Override + public Unit invoke(List types) { + getSupertypeLoopChecker().findLoopsInSupertypesAndDisconnect( + getTypeConstructor(), + types, + new Function1>() { + @Override + public Iterable invoke(TypeConstructor typeConstructor) { + if (typeConstructor.getDeclarationDescriptor() instanceof AbstractTypeParameterDescriptor) { + return ((AbstractTypeParameterDescriptor) typeConstructor.getDeclarationDescriptor()) + .resolveUpperBounds(); + } + return typeConstructor.getSupertypes(); + } + }, + new Function1() { + @Override + public Unit invoke(KotlinType type) { + reportCycleError(type); + return Unit.INSTANCE; + } + } + ); + + if (types.isEmpty()) { + types.add(ErrorUtils.createErrorType("Cyclic upper bounds")); + } + + return null; + } + }); } + @NotNull + protected abstract SupertypeLoopChecker getSupertypeLoopChecker(); + protected abstract void reportCycleError(@NotNull KotlinType type); + @NotNull protected abstract List resolveUpperBounds(); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeParameterDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeParameterDescriptorImpl.java index 2d8e3ad42dd..fb75443810d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeParameterDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeParameterDescriptorImpl.java @@ -16,9 +16,12 @@ package org.jetbrains.kotlin.descriptors.impl; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.SourceElement; +import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.name.Name; @@ -36,6 +39,11 @@ import java.util.List; import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns; public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor { + @Nullable + private final Function1 reportCycleError; + @NotNull + private final SupertypeLoopChecker supertypeLoopsChecker; + public static TypeParameterDescriptor createWithDefaultBound( @NotNull DeclarationDescriptor containingDeclaration, @NotNull Annotations annotations, @@ -60,7 +68,23 @@ public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor int index, @NotNull SourceElement source ) { - return new TypeParameterDescriptorImpl(containingDeclaration, annotations, reified, variance, name, index, source); + return createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index, source, + /* reportCycleError = */ null, SupertypeLoopChecker.EMPTY.INSTANCE); + } + + public static TypeParameterDescriptorImpl createForFurtherModification( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull Annotations annotations, + boolean reified, + @NotNull Variance variance, + @NotNull Name name, + int index, + @NotNull SourceElement source, + @Nullable Function1 reportCycleError, + @NotNull SupertypeLoopChecker supertypeLoopsResolver + ) { + return new TypeParameterDescriptorImpl(containingDeclaration, annotations, reified, variance, name, index, source, reportCycleError, + supertypeLoopsResolver); } private final List upperBounds = new ArrayList(1); @@ -73,9 +97,14 @@ public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor @NotNull Variance variance, @NotNull Name name, int index, - @NotNull SourceElement source + @NotNull SourceElement source, + @Nullable Function1 reportCycleError, + @NotNull SupertypeLoopChecker supertypeLoopsChecker ) { super(LockBasedStorageManager.NO_LOCKS, containingDeclaration, annotations, name, variance, reified, index, source); + this.reportCycleError = reportCycleError; + // ? + this.supertypeLoopsChecker = supertypeLoopsChecker; } @NotNull @@ -130,6 +159,18 @@ public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor } } + @NotNull + @Override + protected SupertypeLoopChecker getSupertypeLoopChecker() { + return supertypeLoopsChecker; + } + + @Override + protected void reportCycleError(@NotNull KotlinType type) { + if (reportCycleError == null) return; + reportCycleError.invoke(type); + } + @NotNull @Override protected List resolveUpperBounds() { diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedTypeParameterDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedTypeParameterDescriptor.kt index 6ed44f6fc89..dbdf07d06bb 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedTypeParameterDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedTypeParameterDescriptor.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.serialization.deserialization.descriptors import org.jetbrains.kotlin.descriptors.SourceElement +import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.AbstractLazyTypeParameterDescriptor @@ -52,4 +53,9 @@ class DeserializedTypeParameterDescriptor( c.typeDeserializer.type(it, Annotations.EMPTY) } } + + override fun getSupertypeLoopChecker() = SupertypeLoopChecker.EMPTY + + override fun reportCycleError(type: KotlinType) = throw IllegalStateException( + "There should be no cycles for deserialized type parameters, but found for: $this") }