From a5c13ce8cf9f0a2ab9057524a9202318206941e3 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 22 Jan 2016 14:42:08 +0300 Subject: [PATCH] Approximate projections in SAM type when creating SAM adapter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the same approach as Java 8 applies to function types (see non-wildcard parametrization in §9.9 of JLS) #KT-6918 Fixed --- .../java/sam/SingleAbstractMethodUtils.java | 46 +++------------- .../java/sam/SingleAbstractMethodUtils.kt | 53 +++++++++++++++++++ .../samByProjectedType/genericInReturnType.kt | 52 ++++++++++++++++++ .../genericInReturnType.txt | 25 +++++++++ .../genericInValueParameter.kt | 32 +++++++++++ .../genericInValueParameter.txt | 25 +++++++++ .../genericSuperWildcard.kt | 25 +++++++++ .../genericSuperWildcard.txt | 23 ++++++++ .../noAdapterBecuaseOfRecursiveUpperBound.kt | 27 ++++++++++ .../noAdapterBecuaseOfRecursiveUpperBound.txt | 22 ++++++++ .../starProjectionComplexUpperBound.kt | 33 ++++++++++++ .../starProjectionComplexUpperBound.txt | 23 ++++++++ .../checkers/DiagnosticsTestGenerated.java | 39 ++++++++++++++ .../org/jetbrains/kotlin/types/TypeUtils.kt | 3 ++ 14 files changed, 390 insertions(+), 38 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SingleAbstractMethodUtils.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.txt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.txt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.txt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.txt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.txt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SingleAbstractMethodUtils.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SingleAbstractMethodUtils.java index 36dd357537b..6fb230f115e 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SingleAbstractMethodUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SingleAbstractMethodUtils.java @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.load.java.structure.*; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils; import org.jetbrains.kotlin.types.*; @@ -37,6 +38,7 @@ import org.jetbrains.kotlin.types.*; import java.util.*; import static org.jetbrains.kotlin.types.Variance.INVARIANT; +import static org.jetbrains.kotlin.types.Variance.IN_VARIANCE; public class SingleAbstractMethodUtils { private SingleAbstractMethodUtils() { @@ -53,38 +55,6 @@ public class SingleAbstractMethodUtils { return abstractMembers; } - private static KotlinType fixProjections(@NotNull KotlinType functionType) { - //removes redundant projection kinds and detects conflicts - - List typeParameters = functionType.getConstructor().getParameters(); - List arguments = new ArrayList(typeParameters.size()); - for (TypeParameterDescriptor typeParameter : typeParameters) { - Variance variance = typeParameter.getVariance(); - TypeProjection argument = functionType.getArguments().get(typeParameter.getIndex()); - Variance kind = argument.getProjectionKind(); - if (kind != INVARIANT && variance != INVARIANT) { - if (kind == variance) { - arguments.add(new TypeProjectionImpl(argument.getType())); - } - else { - return null; - } - } - else { - arguments.add(argument); - } - } - ClassifierDescriptor classifier = functionType.getConstructor().getDeclarationDescriptor(); - assert classifier instanceof ClassDescriptor : "Not class: " + classifier; - return KotlinTypeImpl.create( - functionType.getAnnotations(), - functionType.getConstructor(), - functionType.isMarkedNullable(), - arguments, - ((ClassDescriptor) classifier).getMemberScope(arguments) - ); - } - @Nullable public static KotlinType getFunctionTypeForSamType(@NotNull KotlinType samType) { // e.g. samType == Comparator? @@ -95,13 +65,13 @@ public class SingleAbstractMethodUtils { KotlinType functionTypeDefault = ((JavaClassDescriptor) classifier).getFunctionTypeForSamInterface(); if (functionTypeDefault != null) { + KotlinType noProjectionsSamType = SingleAbstractMethodUtilsKt.nonProjectionParametrization(samType); + if (noProjectionsSamType == null) return null; + // Function2? - KotlinType substitute = TypeSubstitutor.create(samType).substitute(functionTypeDefault, Variance.INVARIANT); - - if (substitute == null) return null; - - KotlinType type = fixProjections(substitute); - if (type == null) return null; + KotlinType type = TypeSubstitutor.create(noProjectionsSamType).substitute(functionTypeDefault, IN_VARIANCE); + assert type != null : "Substitution based on type with no projections '" + noProjectionsSamType + + "' should not end with conflict"; if (FlexibleTypesKt.isNullabilityFlexible(samType)) { return LazyJavaTypeResolver.FlexibleJavaClassifierTypeCapabilities.create(type, TypeUtils.makeNullable(type)); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SingleAbstractMethodUtils.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SingleAbstractMethodUtils.kt new file mode 100644 index 00000000000..a1e6e85f1f5 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SingleAbstractMethodUtils.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.load.java.sam + +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.replace +import org.jetbrains.kotlin.types.typeUtil.asTypeProjection +import org.jetbrains.kotlin.types.typeUtil.containsSpecialType +import org.jetbrains.kotlin.utils.addToStdlib.check + +// If type 'samType' contains no projection, then it's non-projection parametrization is 'samType' itself +// Else each projection type argument 'out/in A_i' (but star projections) is replaced with it's bound 'A_i' +// Star projections are treated specially: +// - If first upper bound of corresponding type parameter does not contain any type parameter of 'samType' class, +// then use this upper bound instead of star projection +// - Otherwise no non-projection parametrization exists for such 'samType' +// +// See Non-wildcard parametrization in §9.9 of JLS 8 for clarification +internal fun nonProjectionParametrization(samType: KotlinType): KotlinType? { + if (samType.arguments.none { it.projectionKind != Variance.INVARIANT }) return samType + val parameters = samType.constructor.parameters + val parametersSet = parameters.toSet() + + return samType.replace( + newArguments = samType.arguments.zip(parameters).map { + val (projection, parameter) = it + when { + projection.projectionKind == Variance.INVARIANT -> projection + + projection.isStarProjection -> + parameter.upperBounds.first().check { + t -> !t.containsSpecialType { it.constructor.declarationDescriptor in parametersSet } + }?.asTypeProjection() ?: return@nonProjectionParametrization null + + else -> projection.type.asTypeProjection() + } + }) +} diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.kt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.kt new file mode 100644 index 00000000000..73739fa4536 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.kt @@ -0,0 +1,52 @@ +// !CHECK_TYPE +// FILE: EventListener.java +public interface EventListener { + E handle(String x); +} + +// FILE: A.java +public class A { + public void foo(EventListener l) { + } + + public static void bar(EventListener l) { + } + + public static void baz(EventListener l) { + } +} + +// FILE: main.kt +fun main() { + A().foo { + x -> 1 + } + + A.bar { + x -> 1 + } + + + // baz + A.baz { + x -> "" // OK + } + + A.baz { + x -> 1 + } + + val block: (String) -> Any? = { + x -> 1 + } + + A().foo(block) + A.bar(block) + + val block2: (String) -> CharSequence? = { + x -> "" + } + + A.baz(block) + A.baz(block2) +} diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.txt new file mode 100644 index 00000000000..0ad00294c80 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.txt @@ -0,0 +1,25 @@ +package + +public /*synthesized*/ fun EventListener(/*0*/ function: (kotlin.String!) -> E!): EventListener +public fun main(): kotlin.Unit + +public open class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ l: EventListener<*>!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun bar(/*0*/ l: ((kotlin.String!) -> kotlin.Any!)!): kotlin.Unit + public open fun bar(/*0*/ l: EventListener<*>!): kotlin.Unit + public final /*synthesized*/ fun baz(/*0*/ l: ((kotlin.String!) -> kotlin.CharSequence!)!): kotlin.Unit + public open fun baz(/*0*/ l: EventListener!): kotlin.Unit +} + +public interface EventListener { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun handle(/*0*/ x: kotlin.String!): E! + 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/j+k/samByProjectedType/genericInValueParameter.kt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.kt new file mode 100644 index 00000000000..1da5559f790 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.kt @@ -0,0 +1,32 @@ +// !CHECK_TYPE +// FILE: EventListener.java +public interface EventListener { + void handle(E e); +} + +// FILE: A.java +public class A { + public void foo(EventListener l) { + } + + public static void bar(EventListener l) { + } + + public static void baz(EventListener l) { + } +} + +// FILE: main.kt +fun main() { + A().foo { + x -> x checkType { _() } + } + + A.bar { + x -> x checkType { _() } + } + + A.baz { + x -> x checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.txt new file mode 100644 index 00000000000..715ff278e3c --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.txt @@ -0,0 +1,25 @@ +package + +public /*synthesized*/ fun EventListener(/*0*/ function: (E!) -> kotlin.Unit): EventListener +public fun main(): kotlin.Unit + +public open class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ l: EventListener<*>!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun bar(/*0*/ l: ((kotlin.Any!) -> kotlin.Unit)!): kotlin.Unit + public open fun bar(/*0*/ l: EventListener<*>!): kotlin.Unit + public final /*synthesized*/ fun baz(/*0*/ l: ((kotlin.CharSequence!) -> kotlin.Unit)!): kotlin.Unit + public open fun baz(/*0*/ l: EventListener!): kotlin.Unit +} + +public interface EventListener { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun handle(/*0*/ e: E!): kotlin.Unit + 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/j+k/samByProjectedType/genericSuperWildcard.kt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.kt new file mode 100644 index 00000000000..df6128944c8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.kt @@ -0,0 +1,25 @@ +// !CHECK_TYPE +// FILE: EventListener.java +public interface EventListener { + void handle(E e); +} + +// FILE: A.java +public class A { + public void foo(EventListener l) { + } + + public static void bar(EventListener l) { + } +} + +// FILE: main.kt +fun main() { + A().foo { + x -> x checkType { _() } + } + + A.bar { + x -> x checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.txt new file mode 100644 index 00000000000..f36e44f7e29 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.txt @@ -0,0 +1,23 @@ +package + +public /*synthesized*/ fun EventListener(/*0*/ function: (E!) -> kotlin.Unit): EventListener +public fun main(): kotlin.Unit + +public open class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ l: EventListener!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun bar(/*0*/ l: ((kotlin.String!) -> kotlin.Unit)!): kotlin.Unit + public open fun bar(/*0*/ l: EventListener!): kotlin.Unit +} + +public interface EventListener { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun handle(/*0*/ e: E!): kotlin.Unit + 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/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.kt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.kt new file mode 100644 index 00000000000..13c1030d12f --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.kt @@ -0,0 +1,27 @@ +// !CHECK_TYPE +// FILE: Function.java +public interface Function> { + E handle(F f); +} + +// FILE: A.java +public class A { + public void foo(Function l) { + } + + public static void bar(Function l) { + } +} + +// FILE: main.kt +fun main() { + A().foo { + x -> + "" + } + + A.bar { + x -> + "" + } +} diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.txt new file mode 100644 index 00000000000..8a0f4680f80 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.txt @@ -0,0 +1,22 @@ +package + +public /*synthesized*/ fun !> Function(/*0*/ function: (F!) -> E!): Function +public fun main(): kotlin.Unit + +public open class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ l: Function<*, *>!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun bar(/*0*/ l: Function<*, *>!): kotlin.Unit +} + +public interface Function!> { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun handle(/*0*/ f: F!): E! + 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/j+k/samByProjectedType/starProjectionComplexUpperBound.kt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.kt new file mode 100644 index 00000000000..e8e43ca9485 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.kt @@ -0,0 +1,33 @@ +// !CHECK_TYPE +// FILE: Function.java +public interface Function, F extends CharSequence> { + F handle(E e); +} + +// FILE: A.java +public class A { + public void foo(Function l) { + } + + public static void bar(Function l) { + } +} + +// FILE: main.kt +fun main() { + A().foo { + x -> + x checkType { _?>() } + "" + } + + A.bar { + x -> + x checkType { _>() } + "" + } + + val block: (Map) -> CharSequence = { x -> "" } + A().foo(block) + A.bar(block) +} diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.txt new file mode 100644 index 00000000000..c5479fd3190 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.txt @@ -0,0 +1,23 @@ +package + +public /*synthesized*/ fun !, /*1*/ F : kotlin.CharSequence!> Function(/*0*/ function: (E!) -> F!): Function +public fun main(): kotlin.Unit + +public open class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ l: Function<*, *>!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun bar(/*0*/ l: ((kotlin.collections.(Mutable)Map!) -> kotlin.CharSequence!)!): kotlin.Unit + public open fun bar(/*0*/ l: Function<*, *>!): kotlin.Unit +} + +public interface Function!, /*1*/ F : kotlin.CharSequence!> { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun handle(/*0*/ e: E!): F! + 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 4fa40c644b5..3668a9aeaba 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10146,6 +10146,45 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/j+k/samByProjectedType") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SamByProjectedType extends AbstractDiagnosticsTest { + public void testAllFilesPresentInSamByProjectedType() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/samByProjectedType"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("genericInReturnType.kt") + public void testGenericInReturnType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInReturnType.kt"); + doTest(fileName); + } + + @TestMetadata("genericInValueParameter.kt") + public void testGenericInValueParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.kt"); + doTest(fileName); + } + + @TestMetadata("genericSuperWildcard.kt") + public void testGenericSuperWildcard() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.kt"); + doTest(fileName); + } + + @TestMetadata("noAdapterBecuaseOfRecursiveUpperBound.kt") + public void testNoAdapterBecuaseOfRecursiveUpperBound() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.kt"); + doTest(fileName); + } + + @TestMetadata("starProjectionComplexUpperBound.kt") + public void testStarProjectionComplexUpperBound() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/j+k/types") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index f617185be69..e0aabb8285e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -144,3 +144,6 @@ fun KotlinType.getImmediateSuperclassNotAny(): KotlinType? { TypeUtils.createSubstitutedSupertype(this, it, TypeSubstitutor.create(this)) } } + +fun KotlinType.asTypeProjection(): TypeProjection = TypeProjectionImpl(this) +fun KotlinType.containsSpecialType(predicate: (KotlinType) -> Boolean) = TypeUtils.containsSpecialType(this, predicate)