diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java index 02c158fb279..6180c8cb4f1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -182,8 +182,8 @@ public class TypeIntersector { parameterUsage.howTheTypeParameterIsUsed.superpose(howTheTypeIsUsedBefore)); return Unit.INSTANCE; }; - processAllTypeParameters(withParameters, Variance.INVARIANT, processor); - processAllTypeParameters(expected, Variance.INVARIANT, processor); + processAllTypeParameters(withParameters, Variance.INVARIANT, processor, parameters::containsKey); + processAllTypeParameters(expected, Variance.INVARIANT, processor, parameters::containsKey); ConstraintSystem.Builder constraintSystem = new ConstraintSystemBuilderImpl(); TypeSubstitutor substitutor = constraintSystem.registerTypeVariables(CallHandle.NONE.INSTANCE, parameters.keySet(), false); constraintSystem.addSubtypeConstraint(withParameters, substitutor.substitute(expected, Variance.INVARIANT), SPECIAL.position()); @@ -191,14 +191,25 @@ public class TypeIntersector { return constraintSystem.build().getStatus().isSuccessful(); } - private static void processAllTypeParameters(KotlinType type, Variance howThisTypeIsUsed, Function1 result) { + private static void processAllTypeParameters( + KotlinType type, + Variance howThisTypeIsUsed, + Function1 result, + Function1 containsParameter + ) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); if (descriptor instanceof TypeParameterDescriptor) { + if (containsParameter.invoke((TypeParameterDescriptor) descriptor)) return; + result.invoke(new TypeParameterUsage((TypeParameterDescriptor) descriptor, howThisTypeIsUsed)); + + for (KotlinType superType : type.getConstructor().getSupertypes()) { + processAllTypeParameters(superType, howThisTypeIsUsed, result, containsParameter); + } } for (TypeProjection projection : type.getArguments()) { if (projection.isStarProjection()) continue; - processAllTypeParameters(projection.getType(), projection.getProjectionKind(), result); + processAllTypeParameters(projection.getType(), projection.getProjectionKind(), result, containsParameter); } } } diff --git a/compiler/testData/diagnostics/tests/cast/IsForTypeWithComplexUpperBound.kt b/compiler/testData/diagnostics/tests/cast/IsForTypeWithComplexUpperBound.kt new file mode 100644 index 00000000000..ae03d44141e --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsForTypeWithComplexUpperBound.kt @@ -0,0 +1,34 @@ +interface A +class B : A {} + +fun > test1(a: U) { + a is B +} + +fun , U : S> test2(a: U) { + a is B +} + +fun , V : A> test3(a: T, b: V) { + a is B + b is B +} + +fun > test4(a: T, b: V) { + a is B + b is B +} + +interface Out +class OutNothing : Out + +fun > test5(a: S) { + a is OutNothing +} + +interface In +class InNothing : In + +fun > test6(a: S) { + a is InNothing +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsForTypeWithComplexUpperBound.txt b/compiler/testData/diagnostics/tests/cast/IsForTypeWithComplexUpperBound.txt new file mode 100644 index 00000000000..7c656ff40d4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsForTypeWithComplexUpperBound.txt @@ -0,0 +1,47 @@ +package + +public fun > test1(/*0*/ a: U): kotlin.Unit +public fun , /*2*/ U : S> test2(/*0*/ a: U): kotlin.Unit +public fun , /*1*/ V : A> test3(/*0*/ a: T, /*1*/ b: V): kotlin.Unit +public fun > test4(/*0*/ a: T, /*1*/ b: V): kotlin.Unit +public fun > test5(/*0*/ a: S): kotlin.Unit +public fun > test6(/*0*/ a: S): kotlin.Unit + +public interface 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 : A { + 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 interface In { + 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 InNothing : In { + public constructor InNothing() + 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 interface Out { + 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 OutNothing : Out { + public constructor OutNothing() + 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/cast/IsWithCycleUpperBounds.kt b/compiler/testData/diagnostics/tests/cast/IsWithCycleUpperBounds.kt new file mode 100644 index 00000000000..598a3e7c21e --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsWithCycleUpperBounds.kt @@ -0,0 +1,14 @@ +// check that there is no SOE on checking for instance +interface Visitor +interface Acceptor + +class Word : Acceptor> + +class V : Visitor + +class S, U : Visitor>(val visitor: U, val acceptor: T) { + fun test() { + visitor is V + acceptor is Word + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsWithCycleUpperBounds.txt b/compiler/testData/diagnostics/tests/cast/IsWithCycleUpperBounds.txt new file mode 100644 index 00000000000..615417e6dfa --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsWithCycleUpperBounds.txt @@ -0,0 +1,37 @@ +package + +public interface Acceptor { + 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 S, /*1*/ U : Visitor> { + public constructor S, /*1*/ U : Visitor>(/*0*/ visitor: U, /*1*/ acceptor: T) + public final val acceptor: T + public final val visitor: U + 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 test(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class V : Visitor { + public constructor V() + 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 interface Visitor { + 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 Word : Acceptor> { + public constructor Word() + 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/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 6f9b67299f0..abb9b090455 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -2902,6 +2902,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("IsForTypeWithComplexUpperBound.kt") + public void testIsForTypeWithComplexUpperBound() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/IsForTypeWithComplexUpperBound.kt"); + doTest(fileName); + } + @TestMetadata("IsRecursionSustainable.kt") public void testIsRecursionSustainable() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/IsRecursionSustainable.kt"); @@ -2914,6 +2920,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("IsWithCycleUpperBounds.kt") + public void testIsWithCycleUpperBounds() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/IsWithCycleUpperBounds.kt"); + doTest(fileName); + } + @TestMetadata("kt614.kt") public void testKt614() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/kt614.kt");