diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index f8e9f258d9e..d80265f92c5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -30,11 +30,11 @@ import kotlin.KotlinPackage; import kotlin.Unit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; import org.jetbrains.kotlin.codegen.context.*; +import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; import org.jetbrains.kotlin.codegen.inline.*; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethod; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; @@ -2610,6 +2610,20 @@ public class ExpressionCodegen extends JetVisitor implem return lookupLocalIndex(declarationDescriptor); } + @Override + public StackValue visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, StackValue data) { + JetType type = bindingContext.get(EXPRESSION_TYPE, expression); + assert type != null; + + assert state.getReflectionTypes().getkClass().getTypeConstructor().equals(type.getConstructor()) + : "::class expression should be type checked to a KClass: " + type; + + ClassifierDescriptor typeArgument = KotlinPackage.single(type.getArguments()).getType().getConstructor().getDeclarationDescriptor(); + assert typeArgument instanceof ClassDescriptor : "KClass argument should be a class: " + typeArgument; + + return generateClassLiteralReference((ClassDescriptor) typeArgument); + } + @Override public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) { ResolvedCall resolvedCall = getResolvedCallWithAssert(expression.getCallableReference(), bindingContext); @@ -2690,10 +2704,22 @@ public class ExpressionCodegen extends JetVisitor implem @Override public Unit invoke(InstructionAdapter v) { v.visitLdcInsn(descriptor.getName().asString()); + StackValue receiverClass = generateClassLiteralReference(containingClass); + receiverClass.put(receiverClass.type, v); + v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false); - Type classAsmType = typeMapper.mapClass(containingClass); + return Unit.INSTANCE$; + } + }); + } - if (containingClass instanceof JavaClassDescriptor) { + @NotNull + private StackValue generateClassLiteralReference(@NotNull final ClassDescriptor descriptor) { + return StackValue.operation(K_CLASS_TYPE, new Function1() { + @Override + public Unit invoke(InstructionAdapter v) { + Type classAsmType = typeMapper.mapClass(descriptor); + if (descriptor instanceof JavaClassDescriptor) { v.aconst(classAsmType); v.invokestatic(REFLECTION, "foreignKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false); } @@ -2701,8 +2727,6 @@ public class ExpressionCodegen extends JetVisitor implem v.getstatic(classAsmType.getInternalName(), JvmAbi.KOTLIN_CLASS_FIELD_NAME, K_CLASS_TYPE.getDescriptor()); } - v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false); - return Unit.INSTANCE$; } }); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.java index e3fdd38d09e..ae0798af134 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.java @@ -117,6 +117,8 @@ public class GenerationState { @Nullable private List earlierScriptsForReplInterpreter; + private final ReflectionTypes reflectionTypes; + private final JvmRuntimeTypes runtimeTypes; @NotNull @@ -187,7 +189,7 @@ public class GenerationState { this.disableParamAssertions = disableParamAssertions; this.generateClassFilter = generateClassFilter; - ReflectionTypes reflectionTypes = new ReflectionTypes(module); + this.reflectionTypes = new ReflectionTypes(module); this.runtimeTypes = new JvmRuntimeTypes(reflectionTypes); } @@ -259,6 +261,11 @@ public class GenerationState { return generateClassFilter; } + @NotNull + public ReflectionTypes getReflectionTypes() { + return reflectionTypes; + } + @NotNull public JvmRuntimeTypes getJvmRuntimeTypes() { return runtimeTypes; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/JetNodeTypes.java b/compiler/frontend/src/org/jetbrains/kotlin/JetNodeTypes.java index 3dc47f9843b..46f07a6b80b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/JetNodeTypes.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/JetNodeTypes.java @@ -135,6 +135,7 @@ public interface JetNodeTypes { JetNodeType INDICES = new JetNodeType("INDICES", JetContainerNode.class); IElementType DOT_QUALIFIED_EXPRESSION = JetStubElementTypes.DOT_QUALIFIED_EXPRESSION; JetNodeType CALLABLE_REFERENCE_EXPRESSION = new JetNodeType("CALLABLE_REFERENCE_EXPRESSION", JetCallableReferenceExpression.class); + JetNodeType CLASS_LITERAL_EXPRESSION = new JetNodeType("CLASS_LITERAL_EXPRESSION", JetClassLiteralExpression.class); JetNodeType SAFE_ACCESS_EXPRESSION = new JetNodeType("SAFE_ACCESS_EXPRESSION", JetSafeQualifiedExpression.class); JetNodeType OBJECT_LITERAL = new JetNodeType("OBJECT_LITERAL", JetObjectLiteralExpression.class); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java index 16a0d4d5c4b..c8b36539eb4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java @@ -1466,7 +1466,7 @@ public class JetControlFlowProcessor { } @Override - public void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression) { + public void visitDoubleColonExpression(@NotNull JetDoubleColonExpression expression) { mark(expression); createNonSyntheticValue(expression, MagicKind.CALLABLE_REFERENCE); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java index 7f752ca4226..797eb00012d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java @@ -376,7 +376,7 @@ public class JetExpressionParsing extends AbstractJetParsing { * : (userType "?"*)? "::" SimpleName * ; */ - private boolean parseCallableReferenceExpression() { + private boolean parseDoubleColonExpression() { PsiBuilder.Marker expression = mark(); if (!at(COLONCOLON)) { @@ -393,8 +393,14 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // COLONCOLON - parseSimpleNameExpression(); - expression.done(CALLABLE_REFERENCE_EXPRESSION); + if (at(CLASS_KEYWORD)) { + advance(); // CLASS_KEYWORD + expression.done(CLASS_LITERAL_EXPRESSION); + } + else { + parseSimpleNameExpression(); + expression.done(CALLABLE_REFERENCE_EXPRESSION); + } return true; } @@ -416,8 +422,8 @@ public class JetExpressionParsing extends AbstractJetParsing { private void parsePostfixExpression() { PsiBuilder.Marker expression = mark(); - boolean callableReference = parseCallableReferenceExpression(); - if (!callableReference) { + boolean doubleColonExpression = parseDoubleColonExpression(); + if (!doubleColonExpression) { parseAtomicExpression(); } @@ -429,7 +435,7 @@ public class JetExpressionParsing extends AbstractJetParsing { parseArrayAccess(); expression.done(ARRAY_ACCESS_EXPRESSION); } - else if (!callableReference && parseCallSuffix()) { + else if (!doubleColonExpression && parseCallSuffix()) { expression.done(CALL_EXPRESSION); } else if (at(DOT)) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetCallableReferenceExpression.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetCallableReferenceExpression.java index 2f78897e8a2..a3ccbf44349 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetCallableReferenceExpression.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetCallableReferenceExpression.java @@ -19,26 +19,12 @@ package org.jetbrains.kotlin.psi; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.JetNodeTypes; -import org.jetbrains.kotlin.lexer.JetTokens; -public class JetCallableReferenceExpression extends JetExpressionImpl { +public class JetCallableReferenceExpression extends JetDoubleColonExpression { public JetCallableReferenceExpression(@NotNull ASTNode node) { super(node); } - @Nullable - public JetTypeReference getTypeReference() { - return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); - } - - @NotNull - public PsiElement getDoubleColonTokenReference() { - //noinspection ConstantConditions - return findChildByType(JetTokens.COLONCOLON); - } - @NotNull public JetSimpleNameExpression getCallableReference() { PsiElement psi = getDoubleColonTokenReference(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetClassLiteralExpression.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetClassLiteralExpression.kt new file mode 100644 index 00000000000..444be0a52d6 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetClassLiteralExpression.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2015 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.psi + +import com.intellij.lang.ASTNode + +public class JetClassLiteralExpression(node: ASTNode) : JetDoubleColonExpression(node) { + override fun accept(visitor: JetVisitor, data: D): R { + return visitor.visitClassLiteralExpression(this, data) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetDoubleColonExpression.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetDoubleColonExpression.kt new file mode 100644 index 00000000000..3a3b058918d --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetDoubleColonExpression.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2015 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.psi + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.JetNodeTypes +import org.jetbrains.kotlin.lexer.JetTokens + +public abstract class JetDoubleColonExpression(node: ASTNode) : JetExpressionImpl(node) { + public fun getTypeReference(): JetTypeReference? = findChildByType(JetNodeTypes.TYPE_REFERENCE) + + public fun getDoubleColonTokenReference(): PsiElement = findChildByType(JetTokens.COLONCOLON) + + override fun accept(visitor: JetVisitor, data: D): R { + return visitor.visitDoubleColonExpression(this, data) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitor.java index 79cf79de17d..2d49fa0ac19 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitor.java @@ -258,10 +258,18 @@ public class JetVisitor extends PsiElementVisitor { return visitExpression(expression, data); } - public R visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, D data) { + public R visitDoubleColonExpression(@NotNull JetDoubleColonExpression expression, D data) { return visitExpression(expression, data); } + public R visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, D data) { + return visitDoubleColonExpression(expression, data); + } + + public R visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, D data) { + return visitDoubleColonExpression(expression, data); + } + public R visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, D data) { return visitQualifiedExpression(expression, data); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoid.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoid.java index 289cfd2370d..4c0ee7c9967 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoid.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoid.java @@ -253,10 +253,18 @@ public class JetVisitorVoid extends JetVisitor { super.visitQualifiedExpression(expression, null); } + public void visitDoubleColonExpression(@NotNull JetDoubleColonExpression expression) { + super.visitDoubleColonExpression(expression, null); + } + public void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression) { super.visitCallableReferenceExpression(expression, null); } + public void visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression) { + super.visitClassLiteralExpression(expression, null); + } + public void visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression) { super.visitDotQualifiedExpression(expression, null); } @@ -758,12 +766,24 @@ public class JetVisitorVoid extends JetVisitor { return null; } + @Override + public final Void visitDoubleColonExpression(@NotNull JetDoubleColonExpression expression, Void data) { + visitDoubleColonExpression(expression); + return null; + } + @Override public final Void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, Void data) { visitCallableReferenceExpression(expression); return null; } + @Override + public final Void visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, Void data) { + visitClassLiteralExpression(expression); + return null; + } + @Override public final Void visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, Void data) { visitDotQualifiedExpression(expression); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoidWithParameter.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoidWithParameter.java index bc086241de6..441017f2776 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoidWithParameter.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoidWithParameter.java @@ -254,10 +254,18 @@ public class JetVisitorVoidWithParameter

extends JetVisitor { super.visitQualifiedExpression(expression, data); } + public void visitDoubleColonExpressionVoid(@NotNull JetDoubleColonExpression expression, P data) { + super.visitDoubleColonExpression(expression, data); + } + public void visitCallableReferenceExpressionVoid(@NotNull JetCallableReferenceExpression expression, P data) { super.visitCallableReferenceExpression(expression, data); } + public void visitClassLiteralExpressionVoid(@NotNull JetClassLiteralExpression expression, P data) { + super.visitClassLiteralExpression(expression, data); + } + public void visitDotQualifiedExpressionVoid(@NotNull JetDotQualifiedExpression expression, P data) { super.visitDotQualifiedExpression(expression, data); } @@ -755,12 +763,24 @@ public class JetVisitorVoidWithParameter

extends JetVisitor { return null; } + @Override + public final Void visitDoubleColonExpression(@NotNull JetDoubleColonExpression expression, P data) { + visitDoubleColonExpressionVoid(expression, data); + return null; + } + @Override public final Void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, P data) { visitCallableReferenceExpressionVoid(expression, data); return null; } + @Override + public final Void visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, P data) { + visitClassLiteralExpressionVoid(expression, data); + return null; + } + @Override public final Void visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, P data) { visitDotQualifiedExpressionVoid(expression, data); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 3c1d650aa80..1721dba98b6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -453,13 +453,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } @Override - public JetTypeInfo visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, ExpressionTypingContext context) { - JetTypeReference typeReference = expression.getTypeReference(); + public JetTypeInfo visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, ExpressionTypingContext context) { + JetType receiverType = resolveDoubleColonExpressionType(expression, context); + // TODO: forbid type parameters & generic classes + ClassifierDescriptor classifier = receiverType.getConstructor().getDeclarationDescriptor(); + return JetTypeInfo.create( + components.reflectionTypes.getKClassType(Annotations.EMPTY, (ClassDescriptor) classifier), + context.dataFlowInfo + ); + } - JetType receiverType = - typeReference == null - ? null - : components.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, false); + @Override + public JetTypeInfo visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, ExpressionTypingContext context) { + JetType receiverType = resolveDoubleColonExpressionType(expression, context); JetSimpleNameExpression callableReference = expression.getCallableReference(); if (callableReference.getReferencedName().isEmpty()) { @@ -472,6 +478,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo); } + @Nullable + private JetType resolveDoubleColonExpressionType(@NotNull JetDoubleColonExpression expression, ExpressionTypingContext context) { + JetTypeReference typeReference = expression.getTypeReference(); + + return typeReference == null + ? null + : components.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, false); + } + @Nullable private JetType getCallableReferenceType( @NotNull JetCallableReferenceExpression expression, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/reflect/ReflectionTypes.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/reflect/ReflectionTypes.kt index 357aafde0a8..db9926a9ad5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/reflect/ReflectionTypes.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/reflect/ReflectionTypes.kt @@ -16,15 +16,16 @@ package org.jetbrains.kotlin.types.reflect -import kotlin.properties.Delegates -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.annotations.Annotations import java.util.ArrayList +import kotlin.properties.Delegates private val KOTLIN_REFLECT_FQ_NAME = FqName("kotlin.reflect") @@ -49,6 +50,7 @@ public class ReflectionTypes(private val module: ModuleDescriptor) { public fun getKExtensionFunction(n: Int): ClassDescriptor = find("KExtensionFunction$n") public fun getKMemberFunction(n: Int): ClassDescriptor = find("KMemberFunction$n") + public val kClass: ClassDescriptor by ClassLookup public val kTopLevelVariable: ClassDescriptor by ClassLookup public val kMutableTopLevelVariable: ClassDescriptor by ClassLookup public val kMemberProperty: ClassDescriptor by ClassLookup @@ -56,6 +58,11 @@ public class ReflectionTypes(private val module: ModuleDescriptor) { public val kTopLevelExtensionProperty: ClassDescriptor by ClassLookup public val kMutableTopLevelExtensionProperty: ClassDescriptor by ClassLookup + public fun getKClassType(annotations: Annotations, classDescriptor: ClassDescriptor): JetType { + val arguments = listOf(TypeProjectionImpl(Variance.INVARIANT, classDescriptor.getDefaultType())) + return JetTypeImpl(annotations, kClass.getTypeConstructor(), false, arguments, kClass.getMemberScope(arguments)) + } + public fun getKFunctionType( annotations: Annotations, receiverType: JetType?, diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/simpleClassLiteral.kt b/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/simpleClassLiteral.kt new file mode 100644 index 00000000000..8833eaf475d --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/simpleClassLiteral.kt @@ -0,0 +1,6 @@ +class A + +fun box(): String { + val klass = A::class + return if (klass.toString() == "class A") "OK" else "Fail: $klass" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/mappedClassIsEqualToClassLiteral.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/mappedClassIsEqualToClassLiteral.kt new file mode 100644 index 00000000000..66fbd963da7 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/mappedClassIsEqualToClassLiteral.kt @@ -0,0 +1,14 @@ +import kotlin.reflect.jvm.* + +class A + +fun box(): String { + val a1 = javaClass().kotlin + val a2 = A::class + + if (a1 != a2) return "Fail equals" + if (a1.hashCode() != a2.hashCode()) return "Fail hashCode" + if (a1.toString() != a2.toString()) return "Fail toString" + + return "OK" +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/classLiteral/simpleClassLiteral.kt b/compiler/testData/diagnostics/testsWithStdLib/classLiteral/simpleClassLiteral.kt new file mode 100644 index 00000000000..ecfe5bc206b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/classLiteral/simpleClassLiteral.kt @@ -0,0 +1,3 @@ +class A + +val k = A::class diff --git a/compiler/testData/diagnostics/testsWithStdLib/classLiteral/simpleClassLiteral.txt b/compiler/testData/diagnostics/testsWithStdLib/classLiteral/simpleClassLiteral.txt new file mode 100644 index 00000000000..b58075164f5 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/classLiteral/simpleClassLiteral.txt @@ -0,0 +1,10 @@ +package + +internal val k: kotlin.reflect.KClass + +internal final class A { + 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 +} diff --git a/compiler/testData/psi/DoubleColon.kt b/compiler/testData/psi/DoubleColon.kt index acb42293fbe..9eee0c27cdc 100644 --- a/compiler/testData/psi/DoubleColon.kt +++ b/compiler/testData/psi/DoubleColon.kt @@ -28,6 +28,11 @@ fun ok() { a??::b a?::c a?::d + + A::class + a::class + ::class + a b ::class } fun err0() { diff --git a/compiler/testData/psi/DoubleColon.txt b/compiler/testData/psi/DoubleColon.txt index 278f3d7554f..3142769b712 100644 --- a/compiler/testData/psi/DoubleColon.txt +++ b/compiler/testData/psi/DoubleColon.txt @@ -464,6 +464,51 @@ JetFile: DoubleColon.kt PsiElement(COLONCOLON)('::') REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('d') + PsiWhiteSpace('\n\n ') + CLASS_LITERAL_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiElement(COLONCOLON)('::') + PsiElement(class)('class') + PsiWhiteSpace('\n ') + CLASS_LITERAL_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(COMMA)(',') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + PsiElement(class)('class') + PsiWhiteSpace('\n ') + CLASS_LITERAL_EXPRESSION + PsiElement(COLONCOLON)('::') + PsiElement(class)('class') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('b') + PsiWhiteSpace(' ') + CLASS_LITERAL_EXPRESSION + PsiElement(COLONCOLON)('::') + PsiElement(class)('class') PsiWhiteSpace('\n') PsiElement(RBRACE)('}') PsiWhiteSpace('\n\n') diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java index ac5b78c4651..e40a125ec59 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java @@ -33,6 +33,7 @@ import java.util.regex.Pattern; @InnerTestClasses({ JetDiagnosticsTestWithStdLibGenerated.Annotations.class, JetDiagnosticsTestWithStdLibGenerated.CallableReference.class, + JetDiagnosticsTestWithStdLibGenerated.ClassLiteral.class, JetDiagnosticsTestWithStdLibGenerated.DuplicateJvmSignature.class, JetDiagnosticsTestWithStdLibGenerated.FunctionLiterals.class, JetDiagnosticsTestWithStdLibGenerated.Inference.class, @@ -598,6 +599,21 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/classLiteral") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ClassLiteral extends AbstractJetDiagnosticsTestWithStdLib { + public void testAllFilesPresentInClassLiteral() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/classLiteral"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("simpleClassLiteral.kt") + public void testSimpleClassLiteral() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/classLiteral/simpleClassLiteral.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 40f94aacae1..af214dd48eb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -2524,6 +2524,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection") @TestDataPath("$PROJECT_ROOT") @InnerTestClasses({ + Reflection.ClassLiterals.class, Reflection.Enclosing.class, Reflection.GenericSignature.class, Reflection.Mapping.class, @@ -2536,6 +2537,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ClassLiterals extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInClassLiterals() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("simpleClassLiteral.kt") + public void testSimpleClassLiteral() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/simpleClassLiteral.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -2712,6 +2728,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("mappedClassIsEqualToClassLiteral.kt") + public void testMappedClassIsEqualToClassLiteral() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/mappedClassIsEqualToClassLiteral.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("memberProperty.kt") public void testMemberProperty() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/memberProperty.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index 853d6a75e6d..e29eb10155d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -178,6 +178,11 @@ public final class ExpressionVisitor extends TranslatorVisitor { return newVar(name, initializer).source(expression); } + @Override + public JsNode visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, @NotNull TranslationContext context) { + throw new UnsupportedOperationException("Class literals are not yet supported: " + expression.getText()); + } + @Override @NotNull public JsNode visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, @NotNull TranslationContext context) {