Don't use ForceResolveUtil.forceResolveAllContents in TypeResolver in order to avoid problems with cyclic hierarchy.
This commit is contained in:
@@ -116,13 +116,42 @@ public class TypeResolver(
|
|||||||
|
|
||||||
if (!type.isBare) {
|
if (!type.isBare) {
|
||||||
for (argument in type.actualType.arguments) {
|
for (argument in type.actualType.arguments) {
|
||||||
ForceResolveUtil.forceResolveAllContents(argument.type)
|
forceResolveTypeContents(argument.type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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 {
|
private fun resolveTypeElement(c: TypeResolutionContext, annotations: Annotations, typeElement: JetTypeElement?): PossiblyBareType {
|
||||||
var result: PossiblyBareType? = null
|
var result: PossiblyBareType? = null
|
||||||
typeElement?.accept(object : JetVisitorVoid() {
|
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
|
if (userType.qualifier != null) { // we must resolve all type references in arguments of qualifier type
|
||||||
for (typeArgument in userType.qualifier!!.typeArguments) {
|
for (typeArgument in userType.qualifier!!.typeArguments) {
|
||||||
typeArgument.typeReference?.let {
|
typeArgument.typeReference?.let {
|
||||||
ForceResolveUtil.forceResolveAllContents(resolveType(scope, it, trace, true))
|
forceResolveTypeContents(resolveType(scope, it, trace, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
open class X<T>
|
||||||
|
|
||||||
|
class A: X<A.B>() {
|
||||||
|
class B
|
||||||
|
}
|
||||||
+22
@@ -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);
|
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")
|
@TestMetadata("twoClassesWithNestedCycle.kt")
|
||||||
public void testTwoClassesWithNestedCycle() throws Exception {
|
public void testTwoClassesWithNestedCycle() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/twoClassesWithNestedCycle.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/twoClassesWithNestedCycle.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user