Don't use ForceResolveUtil.forceResolveAllContents in TypeResolver in order to avoid problems with cyclic hierarchy.

This commit is contained in:
Stanislav Erokhin
2015-10-01 17:15:28 +03:00
parent e24af934dc
commit ace99f6c3f
4 changed files with 64 additions and 2 deletions
@@ -116,13 +116,42 @@ public class TypeResolver(
if (!type.isBare) {
for (argument in type.actualType.arguments) {
ForceResolveUtil.forceResolveAllContents(argument.type)
forceResolveTypeContents(argument.type)
}
}
return type
}
/**
* This function is light version of ForceResolveUtil.forceResolveAllContents
* We can't use ForceResolveUtil.forceResolveAllContents here because it runs ForceResolveUtil.forceResolveAllContents(getConstructor()),
* which is unsafe for some cyclic cases. For Example:
* class A: List<A.B> {
* class B
* }
* Here when we resolve class B, we should resolve supertype for A and we shouldn't start resolve for class B,
* otherwise it would be a cycle.
* Now there is no cycle here because member scope for A is very clever and can get lazy descriptor for class B without resolving it.
*
* todo: find another way after release
*/
private fun forceResolveTypeContents(type: JetType) {
type.annotations // force read type annotations
if (type.isFlexible()) {
forceResolveTypeContents(type.flexibility().lowerBound)
forceResolveTypeContents(type.flexibility().upperBound)
}
else {
type.constructor // force read type constructor
for (projection in type.arguments) {
if (!projection.isStarProjection) {
forceResolveTypeContents(projection.type)
}
}
}
}
private fun resolveTypeElement(c: TypeResolutionContext, annotations: Annotations, typeElement: JetTypeElement?): PossiblyBareType {
var result: PossiblyBareType? = null
typeElement?.accept(object : JetVisitorVoid() {
@@ -343,7 +372,7 @@ public class TypeResolver(
if (userType.qualifier != null) { // we must resolve all type references in arguments of qualifier type
for (typeArgument in userType.qualifier!!.typeArguments) {
typeArgument.typeReference?.let {
ForceResolveUtil.forceResolveAllContents(resolveType(scope, it, trace, true))
forceResolveTypeContents(resolveType(scope, it, trace, true))
}
}
}
@@ -0,0 +1,5 @@
open class X<T>
class A: X<A.B>() {
class B
}
@@ -0,0 +1,22 @@
package
public final class A : X<A.B> {
public constructor A()
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 B {
public constructor B()
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 open class X</*0*/ T> {
public constructor X</*0*/ T>()
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
}
@@ -3381,6 +3381,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("nestedClassInSuperClassParameter.kt")
public void testNestedClassInSuperClassParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/nestedClassInSuperClassParameter.kt");
doTest(fileName);
}
@TestMetadata("twoClassesWithNestedCycle.kt")
public void testTwoClassesWithNestedCycle() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/twoClassesWithNestedCycle.kt");