Inference for some kind of self types
This commit is contained in:
committed by
Victor Petukhov
parent
db72fd1e93
commit
44cf4be1e5
+28
@@ -14175,6 +14175,34 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
public void testTwoTypeConstructors() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/twoTypeConstructors.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SelfTypes {
|
||||
@Test
|
||||
public void testAllFilesPresentInSelfTypes() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("basicInferenceForImplicitSelfType.kt")
|
||||
public void testBasicInferenceForImplicitSelfType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/basicInferenceForImplicitSelfType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("recursiveTypeWithTwoTypeParams.kt")
|
||||
public void testRecursiveTypeWithTwoTypeParams() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/recursiveTypeWithTwoTypeParams.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("writerAppenderExampleRecursive.kt")
|
||||
public void testWriterAppenderExampleRecursive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/writerAppenderExampleRecursive.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+28
@@ -14175,6 +14175,34 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
public void testTwoTypeConstructors() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/twoTypeConstructors.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SelfTypes {
|
||||
@Test
|
||||
public void testAllFilesPresentInSelfTypes() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("basicInferenceForImplicitSelfType.kt")
|
||||
public void testBasicInferenceForImplicitSelfType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/basicInferenceForImplicitSelfType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("recursiveTypeWithTwoTypeParams.kt")
|
||||
public void testRecursiveTypeWithTwoTypeParams() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/recursiveTypeWithTwoTypeParams.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("writerAppenderExampleRecursive.kt")
|
||||
public void testWriterAppenderExampleRecursive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/writerAppenderExampleRecursive.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+39
-5
@@ -293,17 +293,51 @@ class KotlinConstraintSystemCompleter(
|
||||
|
||||
val variableWithConstraints = notFixedTypeVariables.getValue(variableForFixation.variable)
|
||||
|
||||
if (variableForFixation.hasProperConstraint) {
|
||||
fixVariable(this, variableWithConstraints, topLevelAtoms)
|
||||
return true
|
||||
} else {
|
||||
processVariableWhenNotEnoughInformation(this, variableWithConstraints, topLevelAtoms, diagnosticsHolder)
|
||||
when {
|
||||
variableForFixation.hasProperConstraint -> {
|
||||
fixVariable(this, variableWithConstraints, topLevelAtoms)
|
||||
return true
|
||||
}
|
||||
|
||||
hasDeclaredUpperBoundSelfTypes(variableWithConstraints) -> {
|
||||
fixVariable(this, variableWithConstraints, topLevelAtoms)
|
||||
return true
|
||||
}
|
||||
|
||||
else -> processVariableWhenNotEnoughInformation(this, variableWithConstraints, topLevelAtoms, diagnosticsHolder)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun ConstraintSystemCompletionContext.hasDeclaredUpperBoundSelfTypes(variable: VariableWithConstraints): Boolean {
|
||||
val constraints = variable.constraints
|
||||
return constraints.isNotEmpty() && constraints.all {
|
||||
it.position.from is DeclaredUpperBoundConstraintPosition<*> && isSelfType(it.type.typeConstructor())
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConstraintSystemCompletionContext.isSelfType(typeConstructor: TypeConstructorMarker): Boolean {
|
||||
if (typeConstructor.isTypeParameterTypeConstructor()) {
|
||||
val supertype = typeConstructor.supertypes().firstOrNull() ?: return false
|
||||
return isSelfType(supertype.typeConstructor())
|
||||
}
|
||||
|
||||
val parametersCount = typeConstructor.parametersCount()
|
||||
if (parametersCount == 0) return false
|
||||
|
||||
for (parameterId in 0 until parametersCount) {
|
||||
val parameter = typeConstructor.getParameter(parameterId)
|
||||
if (parameter.upperBoundCount() != 1) return false
|
||||
|
||||
val upperBound = parameter.getUpperBound(0)
|
||||
if (upperBound.typeConstructor() == typeConstructor) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun processVariableWhenNotEnoughInformation(
|
||||
c: ConstraintSystemCompletionContext,
|
||||
variableWithConstraints: VariableWithConstraints,
|
||||
|
||||
+10
-10
@@ -12,15 +12,15 @@ class A<T> {
|
||||
}
|
||||
|
||||
fun foo2(a: A<out CharSequence>, b: A<in CharSequence>) {
|
||||
a.foo1(<!TYPE_MISMATCH!>Out<CharSequence>()<!>)
|
||||
a.foo1<<!UPPER_BOUND_VIOLATED!>Out<CharSequence><!>>(<!TYPE_MISMATCH!>Out()<!>)
|
||||
a.foo1(Out<CharSequence>())
|
||||
a.foo1<Out<CharSequence>>(Out())
|
||||
|
||||
a.foo1(Out())
|
||||
a.foo1(Out<Nothing>())
|
||||
|
||||
a.foo2(<!TYPE_MISMATCH!>Inv()<!>)
|
||||
a.foo2(<!TYPE_MISMATCH!>Inv<CharSequence>()<!>)
|
||||
a.foo2<<!UPPER_BOUND_VIOLATED!>Inv<CharSequence><!>>(<!TYPE_MISMATCH!>Inv()<!>)
|
||||
a.foo2(Inv())
|
||||
a.foo2(Inv<CharSequence>())
|
||||
a.foo2<Inv<CharSequence>>(Inv())
|
||||
|
||||
a.foo3(In())
|
||||
a.foo3(In<CharSequence>())
|
||||
@@ -30,13 +30,13 @@ fun foo2(a: A<out CharSequence>, b: A<in CharSequence>) {
|
||||
b.foo1(Out<CharSequence>())
|
||||
b.foo1<Out<CharSequence>>(Out())
|
||||
|
||||
b.foo2(<!TYPE_MISMATCH!>Inv()<!>)
|
||||
b.foo2(<!TYPE_MISMATCH!>Inv<CharSequence>()<!>)
|
||||
b.foo2<<!UPPER_BOUND_VIOLATED!>Inv<CharSequence><!>>(<!TYPE_MISMATCH!>Inv()<!>)
|
||||
b.foo2(Inv())
|
||||
b.foo2(Inv<CharSequence>())
|
||||
b.foo2<Inv<CharSequence>>(Inv())
|
||||
|
||||
|
||||
b.foo3(<!TYPE_MISMATCH!>In<CharSequence>()<!>)
|
||||
b.foo3<<!UPPER_BOUND_VIOLATED!>In<CharSequence><!>>(<!TYPE_MISMATCH!>In()<!>)
|
||||
b.foo3(In<CharSequence>())
|
||||
b.foo3<In<CharSequence>>(In())
|
||||
|
||||
b.foo3(In<Any?>())
|
||||
b.foo3(In())
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
class Builder<B : Builder<B>> {
|
||||
fun <T : B> test(): T = TODO()
|
||||
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
fun testStar(builder: Builder<*>) {
|
||||
builder.test()
|
||||
|
||||
builder
|
||||
.test()
|
||||
.foo()
|
||||
}
|
||||
|
||||
fun <K : Builder<K>> testTypeParam(builder: Builder<K>) {
|
||||
builder.test()
|
||||
|
||||
builder
|
||||
.test()
|
||||
.foo()
|
||||
}
|
||||
|
||||
interface BodySpec<B, S : BodySpec<B, S>> {
|
||||
fun <T : S> isEqualTo(expected: B): T
|
||||
}
|
||||
|
||||
fun test(b: BodySpec<String, *>) {
|
||||
b.isEqualTo("")
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
class Builder<B : Builder<B>> {
|
||||
fun <T : B> test(): T = TODO()
|
||||
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
fun testStar(builder: Builder<*>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("Builder<*>")!>builder.test()<!>
|
||||
|
||||
builder
|
||||
.test()
|
||||
.foo()
|
||||
}
|
||||
|
||||
fun <K : Builder<K>> testTypeParam(builder: Builder<K>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>builder.test()<!>
|
||||
|
||||
builder
|
||||
.test()
|
||||
.foo()
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public fun testStar(/*0*/ builder: Builder<*>): kotlin.Unit
|
||||
public fun </*0*/ K : Builder<K>> testTypeParam(/*0*/ builder: Builder<K>): kotlin.Unit
|
||||
|
||||
public final class Builder</*0*/ B : Builder<B>> {
|
||||
public constructor Builder</*0*/ B : Builder<B>>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun </*0*/ T : B> test(): T
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
interface BodySpec<B, S : BodySpec<B, S>> {
|
||||
fun <T : S> isEqualTo(expected: B): T
|
||||
}
|
||||
|
||||
fun test(b: BodySpec<String, *>) {
|
||||
val x = b.isEqualTo("")
|
||||
x
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
interface BodySpec<B, S : BodySpec<B, S>> {
|
||||
fun <T : S> isEqualTo(expected: B): T
|
||||
}
|
||||
|
||||
fun test(b: BodySpec<String, *>) {
|
||||
val x = b.isEqualTo("")
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("BodySpec<*, *>")!>x<!>
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ b: BodySpec<kotlin.String, *>): kotlin.Unit
|
||||
|
||||
public interface BodySpec</*0*/ B, /*1*/ S : BodySpec<B, S>> {
|
||||
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 abstract fun </*0*/ T : S> isEqualTo(/*0*/ expected: B): T
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
fun test() {
|
||||
WriterAppender.newBuilder()
|
||||
}
|
||||
|
||||
object WriterAppender {
|
||||
class Builder<B : Builder<B>> {
|
||||
fun asBuilder(): B {
|
||||
return this as B
|
||||
}
|
||||
}
|
||||
|
||||
fun <B : Builder<B>> newBuilder(): B {
|
||||
return Builder<B>().asBuilder()
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
fun test() {
|
||||
WriterAppender.<!TYPE_MISMATCH!>newBuilder<!>()
|
||||
}
|
||||
|
||||
object WriterAppender {
|
||||
class Builder<B : Builder<B>> {
|
||||
fun asBuilder(): B {
|
||||
return this <!UNCHECKED_CAST!>as B<!>
|
||||
}
|
||||
}
|
||||
|
||||
fun <B : Builder<B>> newBuilder(): B {
|
||||
return Builder<B>().asBuilder()
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public object WriterAppender {
|
||||
private constructor WriterAppender()
|
||||
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 final fun </*0*/ B : WriterAppender.Builder<B>> newBuilder(): B
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public final class Builder</*0*/ B : WriterAppender.Builder<B>> {
|
||||
public constructor Builder</*0*/ B : WriterAppender.Builder<B>>()
|
||||
public final fun asBuilder(): 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
|
||||
}
|
||||
}
|
||||
Generated
+28
@@ -14181,6 +14181,34 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
public void testTwoTypeConstructors() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/twoTypeConstructors.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SelfTypes {
|
||||
@Test
|
||||
public void testAllFilesPresentInSelfTypes() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("basicInferenceForImplicitSelfType.kt")
|
||||
public void testBasicInferenceForImplicitSelfType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/basicInferenceForImplicitSelfType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("recursiveTypeWithTwoTypeParams.kt")
|
||||
public void testRecursiveTypeWithTwoTypeParams() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/recursiveTypeWithTwoTypeParams.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("writerAppenderExampleRecursive.kt")
|
||||
public void testWriterAppenderExampleRecursive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/writerAppenderExampleRecursive.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -84,7 +84,7 @@ public class DescriptorSubstitutor {
|
||||
for (TypeParameterDescriptor descriptor : typeParameters) {
|
||||
TypeParameterDescriptorImpl substituted = substitutedMap.get(descriptor);
|
||||
for (KotlinType upperBound : descriptor.getUpperBounds()) {
|
||||
KotlinType substitutedBound = substitutor.substitute(upperBound, Variance.IN_VARIANCE);
|
||||
KotlinType substitutedBound = substitutor.substitute(upperBound, Variance.OUT_VARIANCE);
|
||||
if (substitutedBound == null) return null;
|
||||
|
||||
if (substitutedBound != upperBound && wereChanges != null) {
|
||||
|
||||
Reference in New Issue
Block a user