diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 3f338fde003..f427f5cd78b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2330,6 +2330,15 @@ public class ExpressionCodegen extends KtVisitor impleme return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver, resolvedCall); } + if (descriptor instanceof TypeAliasDescriptor) { + ClassDescriptor classDescriptor = ((TypeAliasDescriptor) descriptor).getClassDescriptor(); + if (classDescriptor == null) { + throw new IllegalStateException("Type alias " + descriptor + " static member refernece should be rejected by type checker, " + + "since there is no class corresponding to this type alias."); + } + descriptor = classDescriptor; + } + if (descriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) descriptor; if (isObject(classDescriptor)) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index 0d4e8d9f433..18efdb7dc36 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -654,6 +654,10 @@ class QualifiedExpressionResolver(val classifierUsageCheckers: Iterable PackageQualifier(referenceExpression, descriptor) is ClassDescriptor -> ClassQualifier(referenceExpression, descriptor) is TypeParameterDescriptor -> TypeParameterQualifier(referenceExpression, descriptor) + is TypeAliasDescriptor -> { + val classDescriptor = descriptor.classDescriptor ?: return null + TypeAliasQualifier(referenceExpression, descriptor, classDescriptor) + } else -> return null } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt index 151341aaf29..fb488c24e7d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt @@ -16,10 +16,7 @@ package org.jetbrains.kotlin.resolve.scopes.receivers -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.PackageViewDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector @@ -56,10 +53,12 @@ class TypeParameterQualifier( override fun toString() = "TypeParameter{$descriptor}" } +interface ClassifierQualifier : Qualifier + class ClassQualifier( override val referenceExpression: KtSimpleNameExpression, override val descriptor: ClassDescriptor -) : Qualifier { +) : ClassifierQualifier { override val classValueReceiver: ClassValueReceiver? = descriptor.classValueType?.let { ClassValueReceiver(this, it) } @@ -79,7 +78,21 @@ class ClassQualifier( override fun toString() = "Class{$descriptor}" } -class ClassValueReceiver(val classQualifier: ClassQualifier, private val type: KotlinType) : ExpressionReceiver { +class TypeAliasQualifier( + override val referenceExpression: KtSimpleNameExpression, + override val descriptor: TypeAliasDescriptor, + val classDescriptor: ClassDescriptor +) : ClassifierQualifier { + override val classValueReceiver: ClassValueReceiver? + get() = classDescriptor.classValueType?.let { + ClassValueReceiver(this, it) + } + + override val staticScope: MemberScope + get() = classDescriptor.staticScope +} + +class ClassValueReceiver(val classQualifier: ClassifierQualifier, private val type: KotlinType) : ExpressionReceiver { override fun getType() = type override val expression: KtExpression diff --git a/compiler/testData/codegen/boxAgainstJava/typealias/javaStaticMembersViaTypeAlias.kt b/compiler/testData/codegen/boxAgainstJava/typealias/javaStaticMembersViaTypeAlias.kt new file mode 100644 index 00000000000..75067cb964d --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/typealias/javaStaticMembersViaTypeAlias.kt @@ -0,0 +1,10 @@ +// FILE: JTest.java +public class JTest { + public static String o() { return "O"; } + public static final String K = "K"; +} + +// FILE: 1.kt +typealias JT = JTest + +fun box(): String = JT.o() + JT.K \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/javaStaticMembersViaTypeAlias.kt b/compiler/testData/diagnostics/tests/typealias/javaStaticMembersViaTypeAlias.kt new file mode 100644 index 00000000000..3f7dde38819 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/javaStaticMembersViaTypeAlias.kt @@ -0,0 +1,46 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// FILE: JTest.java +public class JTest { + public static String foo() { return ""; } + public static class Nested {} +} + +// FILE: JDerived.java +public class JDerived extends JTest { +} + +// FILE: test.kt +class KTest { + class Nested + inner class Inner +} + +interface ITest { + class Nested +} + +typealias JT = JTest +typealias JD = JDerived +typealias KT = KTest +typealias IT = ITest + +// Referencing Java class static members via type alias should be ok +val testFoo: String = JT.foo() +val seeAlsoFoo: String = JTest.foo() +// Referencing base Java class static members via type alias for derived Java class should be ok +val testDerivedFoo: String = JD.foo() +val seeAlsoDerivedFoo: String = JDerived.foo() + +// Referencing nested classes via type alias should be prohibited +// (in type position and in expression position) +val testNested1: JT.Nested = JT.Nested() +val testNested2: KT.Nested = KT.Nested() +val testNested3: IT.Nested = IT.Nested() +val testInner1: JT.Inner = JT.Inner() +val testInner2: KT.Inner = KT.Inner() +fun testNestedAsTypeArgument1(x: ListNested>) {} +fun testNestedAsTypeArgument2(x: ListNested>) {} +fun testNestedAsTypeArgument3(x: ListNested>) {} +fun testInnerAsTypeArgument1(x: ListInner>) {} +fun testInnerAsTypeArgument2(x: ListInner>) {} + diff --git a/compiler/testData/diagnostics/tests/typealias/javaStaticMembersViaTypeAlias.txt b/compiler/testData/diagnostics/tests/typealias/javaStaticMembersViaTypeAlias.txt new file mode 100644 index 00000000000..014fa62a5f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/javaStaticMembersViaTypeAlias.txt @@ -0,0 +1,81 @@ +package + +public typealias IT = ITest +public typealias JD = JDerived +public typealias JT = JTest +public typealias KT = KTest +public val seeAlsoDerivedFoo: kotlin.String +public val seeAlsoFoo: kotlin.String +public val testDerivedFoo: kotlin.String +public val testFoo: kotlin.String +public val testInner1: [ERROR : JT.Inner] +public val testInner2: [ERROR : KT.Inner] +public val testNested1: [ERROR : JT.Nested] +public val testNested2: [ERROR : KT.Nested] +public val testNested3: [ERROR : IT.Nested] +public fun testInnerAsTypeArgument1(/*0*/ x: kotlin.collections.List<[ERROR : JT.Inner]>): kotlin.Unit +public fun testInnerAsTypeArgument2(/*0*/ x: kotlin.collections.List<[ERROR : KT.Inner]>): kotlin.Unit +public fun testNestedAsTypeArgument1(/*0*/ x: kotlin.collections.List<[ERROR : JT.Nested]>): kotlin.Unit +public fun testNestedAsTypeArgument2(/*0*/ x: kotlin.collections.List<[ERROR : KT.Nested]>): kotlin.Unit +public fun testNestedAsTypeArgument3(/*0*/ x: kotlin.collections.List<[ERROR : IT.Nested]>): kotlin.Unit + +public interface ITest { + 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 Nested { + public constructor Nested() + 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 JDerived : JTest { + public constructor JDerived() + 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 + + // Static members + public open override /*1*/ /*fake_override*/ fun foo(): kotlin.String! +} + +public open class JTest { + public constructor JTest() + 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 Nested { + public constructor Nested() + 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 + } + + // Static members + public open fun foo(): kotlin.String! +} + +public final class KTest { + public constructor KTest() + 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 inner class Inner { + public constructor Inner() + 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 Nested { + public constructor Nested() + 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 2bc7856df5e..21e7c15e695 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -19953,6 +19953,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("javaStaticMembersViaTypeAlias.kt") + public void testJavaStaticMembersViaTypeAlias() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/javaStaticMembersViaTypeAlias.kt"); + doTest(fileName); + } + @TestMetadata("localTypeAlias.kt") public void testLocalTypeAlias() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/localTypeAlias.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java index 13b39e298e3..75505f7fb54 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java @@ -875,6 +875,21 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxAga } } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/typealias") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Typealias extends AbstractBlackBoxAgainstJavaCodegenTest { + public void testAllFilesPresentInTypealias() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/typealias"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("javaStaticMembersViaTypeAlias.kt") + public void testJavaStaticMembersViaTypeAlias() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/typealias/javaStaticMembersViaTypeAlias.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/visibility") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)