Extract common logic into AbstractTypeConstructor
Mostly it's about detecting loops in supertypes Test data changes: - Loops are being disconnected in Java classes too - functions.kt: loops disconnection mechanism runs supertypes calculation, so when we start check T it forces F' supertypes calculation, that ends with CYCLIC_GENERIC_UPPER_BOUND reported on F #KT-11287 In Progress
This commit is contained in:
@@ -21,25 +21,27 @@ import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
class SupertypeLoopCheckerImpl : SupertypeLoopChecker {
|
||||
override fun findLoopsInSupertypesAndDisconnect(
|
||||
currentTypeConstructor: TypeConstructor,
|
||||
superTypes: MutableCollection<KotlinType>,
|
||||
superTypes: Collection<KotlinType>,
|
||||
neighbors: (TypeConstructor) -> Iterable<KotlinType>,
|
||||
reportLoop: (KotlinType) -> Unit
|
||||
) {
|
||||
|
||||
): Collection<KotlinType> {
|
||||
val graph = DFS.Neighbors<TypeConstructor> { node -> neighbors(node).map { it.constructor } }
|
||||
|
||||
val iterator = superTypes.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val item = iterator.next()
|
||||
if (isReachable(item.constructor, currentTypeConstructor, graph)) {
|
||||
iterator.remove()
|
||||
reportLoop(item)
|
||||
val superTypesToRemove = SmartList<KotlinType>()
|
||||
|
||||
for (superType in superTypes) {
|
||||
if (isReachable(superType.constructor, currentTypeConstructor, graph)) {
|
||||
superTypesToRemove.add(superType)
|
||||
reportLoop(superType)
|
||||
}
|
||||
}
|
||||
|
||||
return if (superTypesToRemove.isEmpty()) superTypes else superTypes - superTypesToRemove
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+34
-97
@@ -21,11 +21,9 @@ import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import kotlin.Unit;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.Mutable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.ReadOnly;
|
||||
@@ -568,59 +566,7 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
||||
return parameters.invoke();
|
||||
}
|
||||
|
||||
private static class Supertypes {
|
||||
@Mutable
|
||||
public final Collection<KotlinType> trueSupertypes;
|
||||
@Mutable
|
||||
public final Collection<KotlinType> allSuperTypes;
|
||||
|
||||
private Supertypes(@Mutable @NotNull Collection<KotlinType> allSuperTypes) {
|
||||
this.trueSupertypes = allSuperTypes;
|
||||
this.allSuperTypes = new ArrayList<KotlinType>(allSuperTypes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<KotlinType> getAllSupertypes() {
|
||||
return allSuperTypes;
|
||||
}
|
||||
}
|
||||
|
||||
private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity {
|
||||
private final NotNullLazyValue<Supertypes> supertypes = c.getStorageManager().createLazyValueWithPostCompute(
|
||||
new Function0<Supertypes>() {
|
||||
@Override
|
||||
public Supertypes invoke() {
|
||||
if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(LazyClassDescriptor.this)) {
|
||||
return new Supertypes(Collections.<KotlinType>emptyList());
|
||||
}
|
||||
|
||||
KtClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
|
||||
if (classOrObject == null) {
|
||||
return new Supertypes(Collections.singleton(c.getModuleDescriptor().getBuiltIns().getAnyType()));
|
||||
}
|
||||
|
||||
List<KotlinType> allSupertypes = c.getDescriptorResolver()
|
||||
.resolveSupertypes(getScopeForClassHeaderResolution(), LazyClassDescriptor.this, classOrObject,
|
||||
c.getTrace());
|
||||
|
||||
return new Supertypes(Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE)));
|
||||
}
|
||||
},
|
||||
new Function1<Boolean, Supertypes>() {
|
||||
@Override
|
||||
public Supertypes invoke(Boolean firstTime) {
|
||||
return new Supertypes(Collections.<KotlinType>emptyList());
|
||||
}
|
||||
},
|
||||
new Function1<Supertypes, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(@NotNull Supertypes supertypes) {
|
||||
findAndDisconnectLoopsInTypeHierarchy(supertypes.trueSupertypes);
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = c.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
|
||||
@Override
|
||||
public List<TypeParameterDescriptor> invoke() {
|
||||
@@ -637,40 +583,37 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
||||
}
|
||||
}, null);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<TypeParameterDescriptor> getParameters() {
|
||||
return parameters.invoke();
|
||||
public LazyClassTypeConstructor() {
|
||||
super(LazyClassDescriptor.this.c.getStorageManager());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<KotlinType> getSupertypes() {
|
||||
return supertypes.invoke().trueSupertypes;
|
||||
protected Collection<KotlinType> computeSupertypes() {
|
||||
if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(LazyClassDescriptor.this)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
KtClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
|
||||
if (classOrObject == null) {
|
||||
return Collections.singleton(c.getModuleDescriptor().getBuiltIns().getAnyType());
|
||||
}
|
||||
|
||||
List<KotlinType> allSupertypes =
|
||||
c.getDescriptorResolver()
|
||||
.resolveSupertypes(getScopeForClassHeaderResolution(), LazyClassDescriptor.this, classOrObject,
|
||||
c.getTrace());
|
||||
|
||||
return Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE));
|
||||
}
|
||||
|
||||
private void findAndDisconnectLoopsInTypeHierarchy(@Mutable Collection<KotlinType> supertypes) {
|
||||
c.getSupertypeLoopChecker().findLoopsInSupertypesAndDisconnect(
|
||||
typeConstructor, supertypes,
|
||||
new Function1<TypeConstructor, Iterable<? extends KotlinType>>() {
|
||||
@Override
|
||||
public Iterable<? extends KotlinType> invoke(TypeConstructor typeConstructor) {
|
||||
return getNeighbors(typeConstructor);
|
||||
}
|
||||
},
|
||||
new Function1<KotlinType, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(KotlinType type) {
|
||||
ClassifierDescriptor supertypeDescriptor = type.getConstructor().getDeclarationDescriptor();
|
||||
if (supertypeDescriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
|
||||
reportCyclicInheritanceHierarchyError(c.getTrace(), LazyClassDescriptor.this, superclass);
|
||||
}
|
||||
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
}
|
||||
);
|
||||
@Override
|
||||
protected void reportSupertypeLoopError(@NotNull KotlinType type) {
|
||||
ClassifierDescriptor supertypeDescriptor = type.getConstructor().getDeclarationDescriptor();
|
||||
if (supertypeDescriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
|
||||
reportCyclicInheritanceHierarchyError(c.getTrace(), LazyClassDescriptor.this, superclass);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportCyclicInheritanceHierarchyError(
|
||||
@@ -704,22 +647,16 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<KotlinType> getNeighbors(TypeConstructor from) {
|
||||
// Supertypes + type for container
|
||||
Collection<KotlinType> neighbours = new ArrayList<KotlinType>(
|
||||
from instanceof LazyClassTypeConstructor
|
||||
? ((LazyClassTypeConstructor) from).supertypes.invoke().getAllSupertypes()
|
||||
: from.getSupertypes()
|
||||
);
|
||||
@NotNull
|
||||
@Override
|
||||
protected SupertypeLoopChecker getSupertypeLoopChecker() {
|
||||
return c.getSupertypeLoopChecker();
|
||||
}
|
||||
|
||||
ClassifierDescriptor fromDescriptor = from.getDeclarationDescriptor();
|
||||
if (fromDescriptor != null) {
|
||||
DeclarationDescriptor container = fromDescriptor.getContainingDeclaration();
|
||||
if (container instanceof ClassDescriptor) {
|
||||
neighbours.add(((ClassDescriptor) container).getDefaultType());
|
||||
}
|
||||
}
|
||||
return neighbours;
|
||||
@NotNull
|
||||
@Override
|
||||
public List<TypeParameterDescriptor> getParameters() {
|
||||
return parameters.invoke();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-9
@@ -52,22 +52,16 @@ public class LazyTypeParameterDescriptor extends AbstractLazyTypeParameterDescri
|
||||
typeParameter.getVariance(),
|
||||
typeParameter.hasModifier(KtTokens.REIFIED_KEYWORD),
|
||||
index,
|
||||
KotlinSourceElementKt.toSourceElement(typeParameter)
|
||||
);
|
||||
KotlinSourceElementKt.toSourceElement(typeParameter),
|
||||
c.getSupertypeLoopChecker());
|
||||
this.c = c;
|
||||
this.typeParameter = typeParameter;
|
||||
|
||||
this.c.getTrace().record(BindingContext.TYPE_PARAMETER, typeParameter, this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected SupertypeLoopChecker getSupertypeLoopChecker() {
|
||||
return c.getSupertypeLoopChecker();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reportCycleError(@NotNull KotlinType type) {
|
||||
protected void reportSupertypeLoopError(@NotNull KotlinType type) {
|
||||
for (KtTypeReference typeReference : getAllUpperBounds()) {
|
||||
if (resolveBoundType(typeReference).getConstructor().equals(type.getConstructor())) {
|
||||
c.getTrace().report(Errors.CYCLIC_GENERIC_UPPER_BOUND.on(typeReference));
|
||||
|
||||
+2
-5
@@ -1,8 +1,6 @@
|
||||
package
|
||||
|
||||
public/*package*/ interface A : C {
|
||||
public abstract override /*1*/ /*fake_override*/ fun bar(): kotlin.Unit
|
||||
public abstract override /*1*/ /*fake_override*/ fun baz(): kotlin.Unit
|
||||
public/*package*/ interface A {
|
||||
public abstract fun foo(): kotlin.Unit
|
||||
}
|
||||
|
||||
@@ -10,7 +8,6 @@ public interface B {
|
||||
public abstract fun bar(): kotlin.Unit
|
||||
}
|
||||
|
||||
public/*package*/ interface C : B {
|
||||
public abstract override /*1*/ /*fake_override*/ fun bar(): kotlin.Unit
|
||||
public/*package*/ interface C {
|
||||
public abstract fun baz(): kotlin.Unit
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package
|
||||
|
||||
public/*package*/ open class J : K {
|
||||
public/*package*/ open class J {
|
||||
public/*package*/ constructor J()
|
||||
public final override /*1*/ /*fake_override*/ fun bar(): kotlin.Unit
|
||||
public/*package*/ open fun foo(): kotlin.Unit
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -5,10 +5,9 @@ public open class I {
|
||||
public final fun foo(): kotlin.Unit
|
||||
}
|
||||
|
||||
public/*package*/ open class J : I {
|
||||
public/*package*/ open class J {
|
||||
public/*package*/ constructor J()
|
||||
public/*package*/ open fun bar(): kotlin.Unit
|
||||
public final override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
|
||||
}
|
||||
|
||||
public open class K {
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ package
|
||||
public interface ExceptionTracker {
|
||||
}
|
||||
|
||||
public/*package*/ open class LockBasedStorageManager : StorageManager {
|
||||
public/*package*/ open class LockBasedStorageManager {
|
||||
public/*package*/ constructor LockBasedStorageManager()
|
||||
@java.lang.Override() public/*package*/ open override /*1*/ fun foo(): kotlin.Unit
|
||||
@java.lang.Override() public/*package*/ open fun foo(): kotlin.Unit
|
||||
|
||||
public/*package*/ interface ExceptionHandlingStrategy {
|
||||
public abstract fun bar(): kotlin.Unit
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
fun <<!CYCLIC_GENERIC_UPPER_BOUND!>T : F?<!>, F : T?> foo1() {}
|
||||
fun <<!CYCLIC_GENERIC_UPPER_BOUND!>T : F?<!>, <!CYCLIC_GENERIC_UPPER_BOUND!>F : T?<!>> foo1() {}
|
||||
|
||||
fun <T : F?, <!CYCLIC_GENERIC_UPPER_BOUND!>F : E<!>, E : F?> foo2() {}
|
||||
fun <T : F?, <!CYCLIC_GENERIC_UPPER_BOUND!>F : E<!>, <!CYCLIC_GENERIC_UPPER_BOUND!>E : F?<!>> foo2() {}
|
||||
|
||||
fun <<!CYCLIC_GENERIC_UPPER_BOUND!>T<!>, F> foo3() where T : F?, F : T {}
|
||||
fun <<!CYCLIC_GENERIC_UPPER_BOUND!>T<!>, <!CYCLIC_GENERIC_UPPER_BOUND!>F<!>> foo3() where T : F?, F : T {}
|
||||
|
||||
fun <T, <!CYCLIC_GENERIC_UPPER_BOUND!>F<!>, E> foo4() where T : F?, F : E, E : F? {}
|
||||
fun <T, <!CYCLIC_GENERIC_UPPER_BOUND!>F<!>, <!CYCLIC_GENERIC_UPPER_BOUND!>E<!>> foo4() where T : F?, F : E, E : F? {}
|
||||
@@ -1,6 +1,6 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : [ERROR : Cyclic upper bounds], /*1*/ F : T?> foo1(): kotlin.Unit
|
||||
public fun </*0*/ T : F?, /*1*/ F : [ERROR : Cyclic upper bounds], /*2*/ E : F?> foo2(): kotlin.Unit
|
||||
public fun </*0*/ T : [ERROR : Cyclic upper bounds], /*1*/ F : T> foo3(): kotlin.Unit
|
||||
public fun </*0*/ T : F?, /*1*/ F : [ERROR : Cyclic upper bounds], /*2*/ E : F?> foo4(): kotlin.Unit
|
||||
public fun </*0*/ T : [ERROR : Cyclic upper bounds], /*1*/ F : [ERROR : Cyclic upper bounds]> foo1(): kotlin.Unit
|
||||
public fun </*0*/ T : F?, /*1*/ F : [ERROR : Cyclic upper bounds], /*2*/ E : [ERROR : Cyclic upper bounds]> foo2(): kotlin.Unit
|
||||
public fun </*0*/ T : [ERROR : Cyclic upper bounds], /*1*/ F : [ERROR : Cyclic upper bounds]> foo3(): kotlin.Unit
|
||||
public fun </*0*/ T : F?, /*1*/ F : [ERROR : Cyclic upper bounds], /*2*/ E : [ERROR : Cyclic upper bounds]> foo4(): kotlin.Unit
|
||||
|
||||
Reference in New Issue
Block a user