From d4c792d0ee8854d9ef3db376239637139c5478b8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 26 Jun 2014 01:55:18 +0400 Subject: [PATCH 01/38] Fix errorlevel returned by kotlinc-*.bat scripts Propagate errorlevel returned as an exit code from the compiler to the outside world. This may not work on Windows XP or earlier, but is required for Windows 7+ --- compiler/cli/bin/kotlinc-js.bat | 2 +- compiler/cli/bin/kotlinc-jvm.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/cli/bin/kotlinc-js.bat b/compiler/cli/bin/kotlinc-js.bat index 94f88d39908..1e10d6b228d 100644 --- a/compiler/cli/bin/kotlinc-js.bat +++ b/compiler/cli/bin/kotlinc-js.bat @@ -42,7 +42,7 @@ if "%_PROFILE_PRELOADER%"=="time" ( org.jetbrains.jet.preloading.Preloader "%_KOTLIN_HOME%\lib\kotlin-compiler.jar;%_KOTLIN_HOME%\lib\kotlin-runtime.jar" ^ org.jetbrains.jet.cli.js.K2JSCompiler 4096 %_PROFILE_PRELOADER% %* ) -exit %ERRORLEVEL% +exit /b %ERRORLEVEL% goto end rem ########################################################################## diff --git a/compiler/cli/bin/kotlinc-jvm.bat b/compiler/cli/bin/kotlinc-jvm.bat index 0d7591e5490..b8c86a00438 100644 --- a/compiler/cli/bin/kotlinc-jvm.bat +++ b/compiler/cli/bin/kotlinc-jvm.bat @@ -42,7 +42,7 @@ if "%_PROFILE_PRELOADER%"=="time" ( org.jetbrains.jet.preloading.Preloader "%_KOTLIN_HOME%\lib\kotlin-compiler.jar;%_KOTLIN_HOME%\lib\kotlin-runtime.jar" ^ org.jetbrains.jet.cli.jvm.K2JVMCompiler 4096 %_PROFILE_PRELOADER% %* ) -exit %ERRORLEVEL% +exit /b %ERRORLEVEL% goto end rem ########################################################################## From 254a95ba1aab9afc6b977228be453e8cadd35eff Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 27 Jun 2014 17:34:52 +0400 Subject: [PATCH 02/38] Improve non-null assertion messages --- core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java b/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java index 585ceea8ef2..efaee67176e 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java @@ -49,7 +49,7 @@ public class Intrinsics { public static void checkFieldIsNotNull(Object value, String className, String fieldName) { if (value == null) { IllegalStateException exception = - new IllegalStateException("Field specified as non-null contains null: " + className + "." + fieldName); + new IllegalStateException("Field specified as non-null is null: " + className + "." + fieldName); throw sanitizeStackTrace(exception); } } @@ -64,7 +64,7 @@ public class Intrinsics { String methodName = caller.getMethodName(); IllegalArgumentException exception = - new IllegalArgumentException("Parameter specified as non-null contains null: " + + new IllegalArgumentException("Parameter specified as non-null is null: " + "method " + className + "." + methodName + ", parameter " + paramName); throw sanitizeStackTrace(exception); From 52dadfc26414d916824a7e456724cca0ae98c872 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 27 Jun 2014 21:42:35 +0400 Subject: [PATCH 03/38] Add test for obsolete issue #KT-3311 Obsolete --- .../testData/diagnostics/tests/j+k/kt3311.kt | 19 +++++++++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++++ 2 files changed, 24 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/j+k/kt3311.kt diff --git a/compiler/testData/diagnostics/tests/j+k/kt3311.kt b/compiler/testData/diagnostics/tests/j+k/kt3311.kt new file mode 100644 index 00000000000..7874ea5c2f0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/kt3311.kt @@ -0,0 +1,19 @@ +// FILE: Super.java +public class Super { + public boolean foo; + public boolean bar; + + public void setFoo(boolean foo) { + this.foo = foo; + } +} + +// FILE: b.kt +public class Sub: Super() { +} + +fun main(args: Array) { + val x = Sub() + x.foo = true + x.bar = true +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 6495690ade4..a119e222184 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -5012,6 +5012,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/j+k/kt3307.kt"); } + @TestMetadata("kt3311.kt") + public void testKt3311() throws Exception { + doTest("compiler/testData/diagnostics/tests/j+k/kt3311.kt"); + } + @TestMetadata("mutableIterator.kt") public void testMutableIterator() throws Exception { doTest("compiler/testData/diagnostics/tests/j+k/mutableIterator.kt"); From aa4d6a4ea7001f1275314a45516b4a5e3853232a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 8 May 2014 22:28:07 +0400 Subject: [PATCH 04/38] Support :: references to properties in frontend #KT-1183 In Progress --- .../jet/lang/reflect/ReflectionTypes.kt | 67 ++++++++--- .../BasicExpressionTypingVisitor.java | 111 ++++++++++++++---- .../property/abstractPropertyViaSubclasses.kt | 32 +++++ .../property/accessViaSubclass.kt | 11 ++ .../property/classFromClass.kt | 8 ++ .../property/extensionFromClass.kt | 11 ++ .../property/extensionFromTopLevel.kt | 22 ++++ .../property/extensionPropertyOnNullable.kt | 8 ++ .../property/genericClass.kt | 12 ++ .../property/javaInstanceField.kt | 23 ++++ .../property/javaStaticFieldViaImport.kt | 25 ++++ .../property/localVariable.kt | 11 ++ .../property/memberFromExtension.kt | 19 +++ .../property/memberFromTopLevel.kt | 21 ++++ .../property/topLevelFromTopLevel.kt | 28 +++++ ...JetDiagnosticsTestWithStdLibGenerated.java | 76 +++++++++++- .../src/kotlin/reflect/KCallable.kt | 21 ++++ .../src/kotlin/reflect/KExtensionProperty.kt | 25 ++++ .../src/kotlin/reflect/KMemberProperty.kt | 25 ++++ .../src/kotlin/reflect/KProperty.kt | 21 ++++ .../src/kotlin/reflect/KTopLevelProperty.kt | 21 ++++ .../src/kotlin/reflect/KVariable.kt | 25 ++++ 22 files changed, 584 insertions(+), 39 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionPropertyOnNullable.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/localVariable.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt create mode 100644 core/reflection/src/kotlin/reflect/KCallable.kt create mode 100644 core/reflection/src/kotlin/reflect/KExtensionProperty.kt create mode 100644 core/reflection/src/kotlin/reflect/KMemberProperty.kt create mode 100644 core/reflection/src/kotlin/reflect/KProperty.kt create mode 100644 core/reflection/src/kotlin/reflect/KTopLevelProperty.kt create mode 100644 core/reflection/src/kotlin/reflect/KVariable.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt b/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt index 9a0d57bdd8c..299d3b2c8fa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt @@ -21,11 +21,10 @@ import org.jetbrains.jet.lang.descriptors.* import org.jetbrains.jet.lang.resolve.name.FqName import org.jetbrains.jet.lang.resolve.name.Name import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.types.* import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns import org.jetbrains.jet.lang.descriptors.annotations.Annotations -import org.jetbrains.jet.lang.types.JetType -import org.jetbrains.jet.lang.types.JetTypeImpl -import org.jetbrains.jet.lang.types.ErrorUtils +import java.util.ArrayList private val KOTLIN_REFLECT_FQ_NAME = FqName("kotlin.reflect") @@ -40,10 +39,23 @@ public class ReflectionTypes(private val module: ModuleDescriptor) { ?: ErrorUtils.createErrorClass(KOTLIN_REFLECT_FQ_NAME.child(name).asString()) } + private object ClassLookup { + fun get(types: ReflectionTypes, property: PropertyMetadata): ClassDescriptor { + return types.find(property.name.capitalize()) + } + } + public fun getKFunction(n: Int): ClassDescriptor = find("KFunction$n") public fun getKExtensionFunction(n: Int): ClassDescriptor = find("KExtensionFunction$n") public fun getKMemberFunction(n: Int): ClassDescriptor = find("KMemberFunction$n") + public val kTopLevelProperty: ClassDescriptor by ClassLookup + public val kMutableTopLevelProperty: ClassDescriptor by ClassLookup + public val kMemberProperty: ClassDescriptor by ClassLookup + public val kMutableMemberProperty: ClassDescriptor by ClassLookup + public val kExtensionProperty: ClassDescriptor by ClassLookup + public val kMutableExtensionProperty: ClassDescriptor by ClassLookup + public fun getKFunctionType( annotations: Annotations, receiverType: JetType?, @@ -51,26 +63,47 @@ public class ReflectionTypes(private val module: ModuleDescriptor) { returnType: JetType, extensionFunction: Boolean ): JetType { - val arguments = KotlinBuiltIns.getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType) - val classDescriptor = correspondingKFunctionClass(receiverType, extensionFunction, parameterTypes.size) + val arity = parameterTypes.size() + val classDescriptor = + if (extensionFunction) getKExtensionFunction(arity) + else if (receiverType != null) getKMemberFunction(arity) + else getKFunction(arity) - return if (ErrorUtils.isError(classDescriptor)) - classDescriptor.getDefaultType() - else - JetTypeImpl(annotations, classDescriptor.getTypeConstructor(), false, arguments, classDescriptor.getMemberScope(arguments)) + if (ErrorUtils.isError(classDescriptor)) { + return classDescriptor.getDefaultType() + } + + val arguments = KotlinBuiltIns.getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType) + return JetTypeImpl(annotations, classDescriptor.getTypeConstructor(), false, arguments, classDescriptor.getMemberScope(arguments)) } - private fun correspondingKFunctionClass( + public fun getKPropertyType( + annotations: Annotations, receiverType: JetType?, - extensionFunction: Boolean, - numberOfParameters: Int - ): ClassDescriptor { - if (extensionFunction) { - return getKExtensionFunction(numberOfParameters) + returnType: JetType, + extensionProperty: Boolean, + mutable: Boolean + ): JetType { + val classDescriptor = if (mutable) when { + extensionProperty -> kMutableExtensionProperty + receiverType != null -> kMutableMemberProperty + else -> kMutableTopLevelProperty } + else when { + extensionProperty -> kExtensionProperty + receiverType != null -> kMemberProperty + else -> kTopLevelProperty + } + + if (ErrorUtils.isError(classDescriptor)) { + return classDescriptor.getDefaultType() + } + + val arguments = ArrayList(2) if (receiverType != null) { - return getKMemberFunction(numberOfParameters) + arguments.add(TypeProjectionImpl(receiverType)) } - return getKFunction(numberOfParameters) + arguments.add(TypeProjectionImpl(returnType)) + return JetTypeImpl(annotations, classDescriptor.getTypeConstructor(), false, arguments, classDescriptor.getMemberScope(arguments)) } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 976d1b5ab19..59cbb914568 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.Annotations; import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator; @@ -472,7 +473,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetSimpleNameExpression reference = expression.getCallableReference(); boolean[] result = new boolean[1]; - FunctionDescriptor descriptor = resolveCallableReferenceTarget(lhsType, context, expression, result); + CallableDescriptor descriptor = resolveCallableReferenceTarget(lhsType, context, expression, result); if (!result[0]) { context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference)); @@ -481,8 +482,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject(); - if (receiverParameter != null && expectedThisObject != null) { - context.trace.report(EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED.on(reference, descriptor)); + if (receiverParameter != null && expectedThisObject != null && descriptor instanceof CallableMemberDescriptor) { + context.trace.report(EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED.on(reference, (CallableMemberDescriptor) descriptor)); return null; } @@ -493,14 +494,37 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { else if (expectedThisObject != null) { receiverType = expectedThisObject.getType(); } + boolean isExtension = receiverParameter != null; + if (descriptor instanceof FunctionDescriptor) { + return createFunctionReferenceType(expression, context, (FunctionDescriptor) descriptor, receiverType, isExtension); + } + else if (descriptor instanceof PropertyDescriptor) { + return createPropertyReferenceType(expression, context, (PropertyDescriptor) descriptor, receiverType, isExtension); + } + else if (descriptor instanceof VariableDescriptor) { + context.trace.report(UNSUPPORTED.on(reference, "References to variables aren't supported yet")); + return null; + } + + throw new UnsupportedOperationException("Callable reference resolved to an unsupported descriptor: " + descriptor); + } + + @Nullable + private JetType createFunctionReferenceType( + @NotNull JetCallableReferenceExpression expression, + @NotNull ExpressionTypingContext context, + @NotNull FunctionDescriptor descriptor, + @Nullable JetType receiverType, + boolean isExtension + ) { //noinspection ConstantConditions JetType type = components.reflectionTypes.getKFunctionType( Annotations.EMPTY, receiverType, getValueParametersTypes(descriptor.getValueParameters()), descriptor.getReturnType(), - receiverParameter != null + isExtension ); if (type.isError()) { @@ -511,7 +535,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { AnonymousFunctionDescriptor functionDescriptor = new AnonymousFunctionDescriptor( context.scope.getContainingDeclaration(), Annotations.EMPTY, - CallableMemberDescriptor.Kind.DECLARATION); + CallableMemberDescriptor.Kind.DECLARATION + ); FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, type, null, Modality.FINAL, Visibilities.PUBLIC); @@ -521,7 +546,32 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } @Nullable - private FunctionDescriptor resolveCallableReferenceTarget( + private JetType createPropertyReferenceType( + @NotNull JetCallableReferenceExpression expression, + @NotNull ExpressionTypingContext context, + @NotNull PropertyDescriptor descriptor, + @Nullable JetType receiverType, + boolean isExtension + ) { + JetType type = components.reflectionTypes.getKPropertyType(Annotations.EMPTY, receiverType, descriptor.getType(), isExtension, + descriptor.isVar()); + + if (type.isError()) { + context.trace.report(REFLECTION_TYPES_NOT_LOADED.on(expression.getDoubleColonTokenReference())); + return null; + } + + LocalVariableDescriptor localVariable = + new LocalVariableDescriptor(context.scope.getContainingDeclaration(), Annotations.EMPTY, Name.special(""), + type, /* mutable = */ false); + + context.trace.record(VARIABLE, expression, localVariable); + + return type; + } + + @Nullable + private CallableDescriptor resolveCallableReferenceTarget( @Nullable JetType lhsType, @NotNull ExpressionTypingContext context, @NotNull JetCallableReferenceExpression expression, @@ -542,7 +592,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ReceiverValue receiver = new TransientReceiver(lhsType); TemporaryTraceAndCache temporaryWithReceiver = TemporaryTraceAndCache.create( context, "trace to resolve callable reference with receiver", reference); - FunctionDescriptor descriptor = resolveCallableNotCheckingArguments( + CallableDescriptor descriptor = resolveCallableNotCheckingArguments( reference, receiver, context.replaceTraceAndCache(temporaryWithReceiver), result); if (result[0]) { temporaryWithReceiver.commit(); @@ -552,7 +602,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetScope staticScope = getStaticNestedClassesScope((ClassDescriptor) classifier); TemporaryTraceAndCache temporaryForStatic = TemporaryTraceAndCache.create( context, "trace to resolve callable reference in static scope", reference); - FunctionDescriptor possibleStaticNestedClassConstructor = resolveCallableNotCheckingArguments(reference, NO_RECEIVER, + CallableDescriptor possibleStaticNestedClassConstructor = resolveCallableNotCheckingArguments(reference, NO_RECEIVER, context.replaceTraceAndCache(temporaryForStatic).replaceScope(staticScope), result); if (result[0]) { temporaryForStatic.commit(); @@ -563,7 +613,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } @Nullable - private FunctionDescriptor resolveCallableNotCheckingArguments( + private CallableDescriptor resolveCallableNotCheckingArguments( @NotNull JetSimpleNameExpression reference, @NotNull ReceiverValue receiver, @NotNull ExpressionTypingContext context, @@ -571,22 +621,41 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ) { Call call = CallMaker.makeCall(reference, receiver, null, reference, ThrowingList.instance()); - TemporaryBindingTrace trace = TemporaryBindingTrace.create(context.trace, "trace to resolve as function", reference); - - ExpressionTypingContext contextForResolve = context.replaceBindingTrace(trace).replaceExpectedType(NO_EXPECTED_TYPE); + TemporaryTraceAndCache funTrace = TemporaryTraceAndCache.create(context, "trace to resolve callable reference as function", + reference); ResolvedCall function = components.expressionTypingServices.getCallExpressionResolver() - .getResolvedCallForFunction(call, reference, contextForResolve, CheckValueArgumentsMode.DISABLED, result); - if (!result[0]) return null; + .getResolvedCallForFunction(call, reference, context.replaceTraceAndCache(funTrace).replaceExpectedType(NO_EXPECTED_TYPE), + CheckValueArgumentsMode.DISABLED, result); + if (result[0]) { + funTrace.commit(); - if (function instanceof VariableAsFunctionResolvedCall) { - // TODO: KProperty - context.trace.report(UNSUPPORTED.on(reference, "References to variables aren't supported yet")); - context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference)); - return null; + if (function instanceof VariableAsFunctionResolvedCall) { + context.trace.report(UNSUPPORTED.on(reference, "References to variables aren't supported yet")); + return null; + } + + return function != null ? function.getResultingDescriptor() : null; } - trace.commit(); - return function != null ? function.getResultingDescriptor() : null; + TemporaryTraceAndCache varTrace = TemporaryTraceAndCache.create(context, "trace to resolve callable reference as variable", + reference); + OverloadResolutionResults variableResults = + components.expressionTypingServices.getCallResolver().resolveSimpleProperty( + BasicCallResolutionContext.create(context.replaceTraceAndCache(varTrace).replaceExpectedType(NO_EXPECTED_TYPE), + call, CheckValueArgumentsMode.DISABLED) + ); + if (!variableResults.isNothing()) { + ResolvedCall variable = + OverloadResolutionResultsUtil.getResultingCall(variableResults, context.contextDependency); + + varTrace.commit(); + if (variable != null) { + result[0] = true; + return variable.getResultingDescriptor(); + } + } + + return null; } @Override diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt new file mode 100644 index 00000000000..5054f0a717c --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt @@ -0,0 +1,32 @@ +trait Base { + val x: Any +} + +class A : Base { + override val x: String = "" +} + +open class B : Base { + override val x: Number = 1.0 +} + +class C : B() { + override val x: Int = 42 +} + +fun test() { + val base = Base::x + base : KMemberProperty + base.get(A()) : Any + base.get(B()) : Number + base.get(C()) : Int + + val a = A::x + a : KMemberProperty + a.get(A()) : String + a.get(B()) : Number + + val b = B::x + b : KMemberProperty + b.get(C()) : Int +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt new file mode 100644 index 00000000000..d3081f85a95 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt @@ -0,0 +1,11 @@ +open class Base { + val foo: Int = 42 +} + +open class Derived : Base() + +fun test() { + val o = Base::foo + o : KMemberProperty + o.get(Derived()) : Int +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt new file mode 100644 index 00000000000..f99c615756a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt @@ -0,0 +1,8 @@ +class A(var g: A) { + val f: Int = 0 + + fun test() { + ::f : KMemberProperty + ::g : KMutableMemberProperty + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt new file mode 100644 index 00000000000..581b698c8e4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt @@ -0,0 +1,11 @@ +class A { + fun test() { + ::foo : KExtensionProperty + ::bar : KMutableExtensionProperty + } +} + +val A.foo: String get() = "" +var A.bar: Int + get() = 42 + set(value) { } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt new file mode 100644 index 00000000000..dc7c5dd3052 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt @@ -0,0 +1,22 @@ +val String.countCharacters: Int + get() = length + +var Int.meaning: Long + get() = 42L + set(value) {} + +fun test() { + val f = String::countCharacters + + f : KExtensionProperty + f : KMutableExtensionProperty + f.get("abc") : Int + f.set("abc", 0) + + val g = Int::meaning + + g : KExtensionProperty + g : KMutableExtensionProperty + g.get(0) : Long + g.set(1, 0L) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionPropertyOnNullable.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionPropertyOnNullable.kt new file mode 100644 index 00000000000..10c3c1de770 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionPropertyOnNullable.kt @@ -0,0 +1,8 @@ +val Any?.meaning: Int + get() = 42 + +fun test() { + val f = Any?::meaning + f.get(null) : Int + f.get("") : Int +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt new file mode 100644 index 00000000000..4e89f7155d6 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt @@ -0,0 +1,12 @@ +class A(val t: T) { + val foo: T = t +} + +fun bar() { + val x = A::foo + x : KMemberProperty, String> + x : KMemberProperty, Any?> + + val y = A<*>::foo + y : KMemberProperty, Any?> +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt new file mode 100644 index 00000000000..fa2f1f436ec --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt @@ -0,0 +1,23 @@ +// FILE: JavaClass.java + +public class JavaClass { + public final int publicFinal; + public long publicMutable; + + protected final double protectedFinal; + protected char protectedMutable; + + private final String privateFinal; + private Object privateMutable; +} + +// FILE: test.kt + +fun test() { + JavaClass::publicFinal : KMemberProperty + JavaClass::publicMutable : KMutableMemberProperty + JavaClass::protectedFinal : KMemberProperty + JavaClass::protectedMutable : KMutableMemberProperty + JavaClass::privateFinal : KMemberProperty + JavaClass::privateMutable : KMutableMemberProperty +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt new file mode 100644 index 00000000000..555b296f0c6 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt @@ -0,0 +1,25 @@ +// FILE: JavaClass.java + +public class JavaClass { + public static final String publicFinal; + public static volatile Object publicMutable; + + protected static final double protectedFinal; + protected static char protectedMutable; + + private static final JavaClass privateFinal; + private static Throwable privateMutable; +} + +// FILE: test.kt + +import JavaClass.* + +fun test() { + ::publicFinal : KTopLevelProperty + ::publicMutable : KMutableTopLevelProperty + ::protectedFinal : KProperty + ::protectedMutable : KMutableProperty + ::privateFinal : KProperty + ::privateMutable : KMutableProperty +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/localVariable.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/localVariable.kt new file mode 100644 index 00000000000..5550b022d63 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/localVariable.kt @@ -0,0 +1,11 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE + +fun test(param: String) { + val a = ::param + + val local = "local" + val b = ::local + + val lambda = { -> } + val g = ::lambda +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt new file mode 100644 index 00000000000..091e60a2893 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt @@ -0,0 +1,19 @@ +class A { + val foo: Unit = Unit.VALUE + var bar: String = "" + var self: A + get() = this + set(value) { } +} + +fun A.test() { + val x = ::foo + val y = ::bar + val z = ::self + + x : KMemberProperty + y : KMutableMemberProperty + z : KMutableMemberProperty + + y.set(z.get(A()), x.get(A()).toString()) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt new file mode 100644 index 00000000000..93e5bb0601c --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt @@ -0,0 +1,21 @@ +class A { + val foo: Int = 42 + var bar: String = "" +} + +fun test() { + val p = A::foo + + p : KMemberProperty + p : KMutableMemberProperty + p.get(A()) : Int + p.get() + p.set(A(), 239) + + val q = A::bar + + q : KMemberProperty + q : KMutableMemberProperty + q.get(A()): String + q.set(A(), "q") +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt new file mode 100644 index 00000000000..85ef42b4398 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt @@ -0,0 +1,28 @@ +var x: Int = 42 +val y: String get() = "y" + +fun testX() { + val xx = ::x + xx : KMutableTopLevelProperty + xx : KTopLevelProperty + xx : KMutableProperty + xx : KProperty + xx : KCallable + + xx.name : String + xx.get() : Int + xx.set(239) +} + +fun testY() { + val yy = ::y + yy : KMutableTopLevelProperty + yy : KTopLevelProperty + yy : KMutableProperty + yy : KProperty + yy : KCallable + + yy.name : String + yy.get() : String + yy.set("yy") +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java index ed8963048ac..7bc1d1161ba 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java @@ -105,7 +105,7 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic } @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/callableReference") - @InnerTestClasses({CallableReference.Function.class}) + @InnerTestClasses({CallableReference.Function.class, CallableReference.Property.class}) public static class CallableReference extends AbstractJetDiagnosticsTestWithStdLib { public void testAllFilesPresentInCallableReference() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/testsWithStdLib/callableReference"), Pattern.compile("^(.+)\\.kt$"), true); @@ -359,10 +359,84 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/callableReference/property") + public static class Property extends AbstractJetDiagnosticsTestWithStdLib { + @TestMetadata("abstractPropertyViaSubclasses.kt") + public void testAbstractPropertyViaSubclasses() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt"); + } + + @TestMetadata("accessViaSubclass.kt") + public void testAccessViaSubclass() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt"); + } + + public void testAllFilesPresentInProperty() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/testsWithStdLib/callableReference/property"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("classFromClass.kt") + public void testClassFromClass() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt"); + } + + @TestMetadata("extensionFromClass.kt") + public void testExtensionFromClass() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt"); + } + + @TestMetadata("extensionFromTopLevel.kt") + public void testExtensionFromTopLevel() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt"); + } + + @TestMetadata("extensionPropertyOnNullable.kt") + public void testExtensionPropertyOnNullable() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionPropertyOnNullable.kt"); + } + + @TestMetadata("genericClass.kt") + public void testGenericClass() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt"); + } + + @TestMetadata("javaInstanceField.kt") + public void testJavaInstanceField() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt"); + } + + @TestMetadata("javaStaticFieldViaImport.kt") + public void testJavaStaticFieldViaImport() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt"); + } + + @TestMetadata("localVariable.kt") + public void testLocalVariable() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/localVariable.kt"); + } + + @TestMetadata("memberFromExtension.kt") + public void testMemberFromExtension() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt"); + } + + @TestMetadata("memberFromTopLevel.kt") + public void testMemberFromTopLevel() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt"); + } + + @TestMetadata("topLevelFromTopLevel.kt") + public void testTopLevelFromTopLevel() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt"); + } + + } + public static Test innerSuite() { TestSuite suite = new TestSuite("CallableReference"); suite.addTestSuite(CallableReference.class); suite.addTestSuite(Function.class); + suite.addTestSuite(Property.class); return suite; } } diff --git a/core/reflection/src/kotlin/reflect/KCallable.kt b/core/reflection/src/kotlin/reflect/KCallable.kt new file mode 100644 index 00000000000..7c2cea54c38 --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KCallable.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KCallable { + public val name: String +} diff --git a/core/reflection/src/kotlin/reflect/KExtensionProperty.kt b/core/reflection/src/kotlin/reflect/KExtensionProperty.kt new file mode 100644 index 00000000000..a2791873ccb --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KExtensionProperty.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KExtensionProperty : KProperty { + public fun get(receiver: T): R +} + +public trait KMutableExtensionProperty : KExtensionProperty, KMutableProperty { + public fun set(receiver: T, value: R) +} diff --git a/core/reflection/src/kotlin/reflect/KMemberProperty.kt b/core/reflection/src/kotlin/reflect/KMemberProperty.kt new file mode 100644 index 00000000000..233a369617f --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KMemberProperty.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KMemberProperty : KProperty { + public fun get(receiver: T): R +} + +public trait KMutableMemberProperty : KMemberProperty, KMutableProperty { + public fun set(receiver: T, value: R) +} diff --git a/core/reflection/src/kotlin/reflect/KProperty.kt b/core/reflection/src/kotlin/reflect/KProperty.kt new file mode 100644 index 00000000000..8253bb0669b --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KProperty.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KProperty : KCallable + +public trait KMutableProperty : KProperty diff --git a/core/reflection/src/kotlin/reflect/KTopLevelProperty.kt b/core/reflection/src/kotlin/reflect/KTopLevelProperty.kt new file mode 100644 index 00000000000..ee1bf17b6b7 --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KTopLevelProperty.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KTopLevelProperty : KVariable + +public trait KMutableTopLevelProperty : KTopLevelProperty, KMutableVariable diff --git a/core/reflection/src/kotlin/reflect/KVariable.kt b/core/reflection/src/kotlin/reflect/KVariable.kt new file mode 100644 index 00000000000..4c8fcbb4851 --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KVariable.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KVariable : KProperty { + public fun get(): R +} + +public trait KMutableVariable : KVariable, KMutableProperty { + public fun set(value: R) +} From 4ef089d2ed3212a7d358d9584ca5614645ae3058 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 19 May 2014 17:46:02 +0400 Subject: [PATCH 05/38] Introduce KClass, KPackage and their JVM implementations --- core/reflection/src/kotlin/reflect/KClass.kt | 19 +++++++++++++++++ .../reflection/src/kotlin/reflect/KPackage.kt | 19 +++++++++++++++++ .../kotlin/reflect/jvm/internal/KClassImpl.kt | 21 +++++++++++++++++++ .../reflect/jvm/internal/KPackageImpl.kt | 21 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 core/reflection/src/kotlin/reflect/KClass.kt create mode 100644 core/reflection/src/kotlin/reflect/KPackage.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt diff --git a/core/reflection/src/kotlin/reflect/KClass.kt b/core/reflection/src/kotlin/reflect/KClass.kt new file mode 100644 index 00000000000..300a7415841 --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KClass.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KClass diff --git a/core/reflection/src/kotlin/reflect/KPackage.kt b/core/reflection/src/kotlin/reflect/KPackage.kt new file mode 100644 index 00000000000..cb176d1543c --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KPackage.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KPackage diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt new file mode 100644 index 00000000000..084a36d0ed1 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +class KClassImpl( + val jClass: Class +) : KClass diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt new file mode 100644 index 00000000000..1bd38d78641 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +class KPackageImpl( + val jClass: Class<*> +) : KPackage From 59777e7df641b962ca50285b5d92f72202b2ead2 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 20 May 2014 20:20:53 +0400 Subject: [PATCH 06/38] Generate "$kotlinClass"/"$kotlinPackage" reflection fields to every class Some seemingly irrelevant tests were changed because now there's in almost every class and class initialization begins with executing it --- .../codegen/ImplementationBodyCodegen.java | 19 +++++--- .../jetbrains/jet/codegen/MemberCodegen.java | 27 +++++++++-- .../jetbrains/jet/codegen/PackageCodegen.java | 45 ++++++++++++++----- .../jet/codegen/inline/InlineCodegenUtil.java | 5 ++- .../lang/resolve/java/AsmTypeConstants.java | 3 ++ .../jetbrains/kotlin/CompilerSmokeTest.java | 9 ++-- .../testData/codegen/bytecodeText/kt2202.kt | 2 +- .../bytecodeText/privateDefaultArgs.kt | 2 +- .../jet/codegen/PropertyGenTest.java | 6 +-- .../jet/lang/resolve/java/JvmAbi.java | 2 + .../tinyApp/outs/memberFunFromTopLevel.out | 4 +- .../tinyApp/outs/memberGetterFromTopLevel.out | 4 +- .../src/stepInto/memberFunFromTopLevel.kt | 2 + .../src/stepInto/memberGetterFromTopLevel.kt | 2 + .../jet/jps/build/KotlinJpsBuildTest.java | 4 +- .../module1/src/a.kt | 2 +- .../module2/src/b.kt | 2 +- 17 files changed, 99 insertions(+), 41 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 6650d907bfb..a125ab0f0f2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -72,8 +72,7 @@ import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; -import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; -import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; +import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.DelegationToTraitImpl; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; @@ -429,7 +428,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { @Override protected void generateSyntheticParts() { - generateDelegatedPropertyMetadataArray(); + generateStaticSyntheticFields(); generateFieldForSingleton(); @@ -463,10 +462,20 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateToArray(); - genClosureFields(context.closure, v, state.getTypeMapper()); + genClosureFields(context.closure, v, typeMapper); } - private void generateDelegatedPropertyMetadataArray() { + private void generateStaticSyntheticFields() { + if (isAnnotationClass(descriptor)) { + // There's a bug in JDK 6 and 7 that prevents us from generating a static field in an annotation class: + // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6857918 + // TODO: make reflection work on annotation classes somehow + return; + } + + generateReflectionObjectField(state, classAsmType, v, K_CLASS_IMPL_TYPE, JvmAbi.KOTLIN_CLASS_FIELD_NAME, + createOrGetClInitCodegen().v); + generatePropertyMetadataArrayFieldIfNeeded(classAsmType); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index b491052aabb..622b710fe57 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -50,12 +50,12 @@ import java.util.List; import static org.jetbrains.jet.codegen.AsmUtil.boxType; import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.TraitImpl; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED; import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.TraitImpl; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public abstract class MemberCodegen extends ParentCodegenAware { @@ -316,6 +316,27 @@ public abstract class MemberCodegen", "(Ljava/lang/Class;)V", false); + v.putstatic(thisAsmType.getInternalName(), fieldName, kImplType.getDescriptor()); + } + protected void generatePropertyMetadataArrayFieldIfNeeded(@NotNull Type thisAsmType) { List delegatedProperties = new ArrayList(); for (JetDeclaration declaration : ((JetDeclarationContainer) element).getDeclarations()) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java index c46ae090f6b..24a8e07baf2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java @@ -56,27 +56,32 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.org.objectweb.asm.AnnotationVisitor; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import java.util.*; import static org.jetbrains.jet.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses; import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; +import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.K_PACKAGE_IMPL_TYPE; import static org.jetbrains.jet.lang.resolve.java.PackageClassUtils.getPackageClassFqName; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.*; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class PackageCodegen { - private final GenerationState state; private final ClassBuilderOnDemand v; + private final GenerationState state; private final Collection files; + private final Type packageClassType; private final PackageFragmentDescriptor packageFragment; private final PackageFragmentDescriptor compiledPackageFragment; private final List previouslyCompiledCallables; - public PackageCodegen(@NotNull GenerationState state, @NotNull Collection files, @NotNull final FqName fqName) { + public PackageCodegen(@NotNull GenerationState state, @NotNull Collection files, @NotNull FqName fqName) { this.state = state; this.files = files; this.packageFragment = getOnlyPackageFragment(fqName); + this.packageClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(getPackageClassFqName(fqName)); this.compiledPackageFragment = getCompiledPackageFragment(fqName); this.previouslyCompiledCallables = filterDeserializedCallables(compiledPackageFragment); @@ -88,14 +93,13 @@ public class PackageCodegen { Collection files = PackageCodegen.this.files; JetFile sourceFile = getRepresentativePackageFile(files); - String className = AsmUtil.internalNameByFqNameWithoutInnerClasses(getPackageClassFqName(fqName)); - ClassBuilder v = PackageCodegen.this.state.getFactory() - .newVisitor( - PackageFacade(packageFragment == null ? compiledPackageFragment : packageFragment), - Type.getObjectType(className), PackagePartClassUtils.getPackageFilesWithCallables(files)); + ClassBuilder v = PackageCodegen.this.state.getFactory().newVisitor( + PackageFacade(packageFragment == null ? compiledPackageFragment : packageFragment), + packageClassType, PackagePartClassUtils.getPackageFilesWithCallables(files) + ); v.defineClass(sourceFile, V1_6, ACC_PUBLIC | ACC_FINAL, - className, + packageClassType.getInternalName(), null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY @@ -216,18 +220,35 @@ public class PackageCodegen { } } - generateDelegationsToPreviouslyCompiled(generateCallableMemberTasks); + if (!generateCallableMemberTasks.isEmpty()) { + generatePackageFacadeClass(generateCallableMemberTasks, bindings); + } + } - if (generateCallableMemberTasks.isEmpty()) return; + private void generatePackageFacadeClass( + @NotNull Map tasks, + @NotNull List bindings + ) { + generateKotlinPackageReflectionField(); - for (CallableMemberDescriptor member : Ordering.from(MemberComparator.INSTANCE).sortedCopy(generateCallableMemberTasks.keySet())) { - generateCallableMemberTasks.get(member).run(); + generateDelegationsToPreviouslyCompiled(tasks); + + for (CallableMemberDescriptor member : Ordering.from(MemberComparator.INSTANCE).sortedCopy(tasks.keySet())) { + tasks.get(member).run(); } bindings.add(v.getSerializationBindings()); writeKotlinPackageAnnotationIfNeeded(JvmSerializationBindings.union(bindings)); } + private void generateKotlinPackageReflectionField() { + MethodVisitor mv = v.newMethod(NO_ORIGIN, ACC_STATIC, "", "()V", null, null); + MemberCodegen.generateReflectionObjectField(state, packageClassType, v, K_PACKAGE_IMPL_TYPE, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, + new InstructionAdapter(mv)); + mv.visitInsn(RETURN); + FunctionCodegen.endVisit(mv, "static initializer", null); + } + private void writeKotlinPackageAnnotationIfNeeded(@NotNull JvmSerializationBindings bindings) { if (state.getClassBuilderMode() != ClassBuilderMode.FULL) { return; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java index 4cbaceed56b..c1871be9e64 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java @@ -266,6 +266,9 @@ public class InlineCodegenUtil { } public static boolean isCapturedFieldName(@NotNull String fieldName) { - return fieldName.startsWith(CAPTURED_FIELD_PREFIX) || THIS$0.equals(fieldName) || RECEIVER$0.equals(fieldName); + // TODO: improve this heuristic + return (fieldName.startsWith(CAPTURED_FIELD_PREFIX) && !fieldName.equals(JvmAbi.KOTLIN_CLASS_FIELD_NAME)) || + THIS$0.equals(fieldName) || + RECEIVER$0.equals(fieldName); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index 873dff87312..d9a1f950fcc 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -38,6 +38,9 @@ public class AsmTypeConstants { public static final Type PROPERTY_METADATA_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadata"); public static final Type PROPERTY_METADATA_IMPL_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadataImpl"); + public static final Type K_CLASS_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KClassImpl"); + public static final Type K_PACKAGE_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KPackageImpl"); + public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef"); public static Type getType(@NotNull Class javaClass) { diff --git a/compiler/integration-tests/src/org/jetbrains/kotlin/CompilerSmokeTest.java b/compiler/integration-tests/src/org/jetbrains/kotlin/CompilerSmokeTest.java index f9c87e96f20..6b544d4500e 100644 --- a/compiler/integration-tests/src/org/jetbrains/kotlin/CompilerSmokeTest.java +++ b/compiler/integration-tests/src/org/jetbrains/kotlin/CompilerSmokeTest.java @@ -20,15 +20,14 @@ import org.junit.Test; import java.io.File; -import static junit.framework.Assert.*; +import static org.junit.Assert.assertEquals; public class CompilerSmokeTest extends KotlinIntegrationTestBase { - @Test public void compileAndRunHelloApp() throws Exception { String jar = tmpdir.getTmpDir().getAbsolutePath() + File.separator + "hello.jar"; - assertEquals("compilation failed", 0, runCompiler("hello.compile", "-src", "hello.kt", "-jar", jar)); + assertEquals("compilation failed", 0, runCompiler("hello.compile", "-includeRuntime", "hello.kt", "-jar", jar)); runJava("hello.run", "-cp", jar, "Hello.HelloPackage"); } @@ -36,7 +35,7 @@ public class CompilerSmokeTest extends KotlinIntegrationTestBase { public void compileAndRunHelloAppFQMain() throws Exception { String jar = tmpdir.getTmpDir().getAbsolutePath() + File.separator + "hello.jar"; - assertEquals("compilation failed", 0, runCompiler("hello.compile", "-src", "hello.kt", "-jar", jar)); + assertEquals("compilation failed", 0, runCompiler("hello.compile", "-includeRuntime", "hello.kt", "-jar", jar)); runJava("hello.run", "-cp", jar, "Hello.HelloPackage"); } @@ -44,7 +43,7 @@ public class CompilerSmokeTest extends KotlinIntegrationTestBase { public void compileAndRunHelloAppVarargMain() throws Exception { String jar = tmpdir.getTmpDir().getAbsolutePath() + File.separator + "hello.jar"; - assertEquals("compilation failed", 0, runCompiler("hello.compile", "-src", "hello.kt", "-jar", jar)); + assertEquals("compilation failed", 0, runCompiler("hello.compile", "-includeRuntime", "hello.kt", "-jar", jar)); runJava("hello.run", "-cp", jar, "Hello.HelloPackage"); } diff --git a/compiler/testData/codegen/bytecodeText/kt2202.kt b/compiler/testData/codegen/bytecodeText/kt2202.kt index 2d62a6e896b..e2bc119b688 100644 --- a/compiler/testData/codegen/bytecodeText/kt2202.kt +++ b/compiler/testData/codegen/bytecodeText/kt2202.kt @@ -18,4 +18,4 @@ class B { } // 0 INVOKEVIRTUAL -// 4 INVOKESPECIAL +// 2 INVOKESPECIAL [AB]\. diff --git a/compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt b/compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt index 699df18dff9..633b067a1be 100644 --- a/compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt +++ b/compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt @@ -13,4 +13,4 @@ fun box(): String { } // 0 INVOKEVIRTUAL -// 3 INVOKESPECIAL +// 2 INVOKESPECIAL B\.foo diff --git a/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index a03cf5e89e4..242c52c6794 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -40,11 +40,7 @@ public class PropertyGenTest extends CodegenTestCase { public void testPrivateVal() throws Exception { loadFile(); - Class aClass = generateClass("PrivateVal"); - Field[] fields = aClass.getDeclaredFields(); - assertEquals(1, fields.length); // prop - Field field = fields[0]; - assertEquals("prop", field.getName()); + generateClass("PrivateVal").getDeclaredField("prop"); } public void testPrivateVar() throws Exception { diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java index 49e8d8f3874..4cb17862e6c 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java @@ -45,6 +45,8 @@ public final class JvmAbi { public static final String CLASS_OBJECT_FIELD = "object$"; public static final FqName K_OBJECT = new FqName("kotlin.jvm.internal.KObject"); + public static final String KOTLIN_CLASS_FIELD_NAME = "$kotlinClass"; + public static final String KOTLIN_PACKAGE_FIELD_NAME = "$kotlinPackage"; public static boolean isClassObjectFqName(@NotNull FqName fqName) { return fqName.lastSegmentIs(Name.identifier(CLASS_OBJECT_CLASS_NAME)); diff --git a/idea/testData/debugger/tinyApp/outs/memberFunFromTopLevel.out b/idea/testData/debugger/tinyApp/outs/memberFunFromTopLevel.out index c2e52ded0b3..4f55a285f35 100644 --- a/idea/testData/debugger/tinyApp/outs/memberFunFromTopLevel.out +++ b/idea/testData/debugger/tinyApp/outs/memberFunFromTopLevel.out @@ -1,7 +1,7 @@ -LineBreakpoint created at memberFunFromTopLevel.kt:11 +LineBreakpoint created at memberFunFromTopLevel.kt:13 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! memberFunFromTopLevel.MemberFunFromTopLevelPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' -memberFunFromTopLevel.kt:10 +memberFunFromTopLevel.kt:12 memberFunFromTopLevel.kt:4 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' diff --git a/idea/testData/debugger/tinyApp/outs/memberGetterFromTopLevel.out b/idea/testData/debugger/tinyApp/outs/memberGetterFromTopLevel.out index 72ee47c8875..7699e7232f3 100644 --- a/idea/testData/debugger/tinyApp/outs/memberGetterFromTopLevel.out +++ b/idea/testData/debugger/tinyApp/outs/memberGetterFromTopLevel.out @@ -1,7 +1,7 @@ -LineBreakpoint created at memberGetterFromTopLevel.kt:13 +LineBreakpoint created at memberGetterFromTopLevel.kt:15 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! memberGetterFromTopLevel.MemberGetterFromTopLevelPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' -memberGetterFromTopLevel.kt:12 +memberGetterFromTopLevel.kt:14 memberGetterFromTopLevel.kt:5 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' diff --git a/idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt b/idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt index 0ab3d10e410..6dfc6d4cb91 100644 --- a/idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt +++ b/idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt @@ -7,6 +7,8 @@ class A { } fun main(args: Array) { + A() + //Breakpoint! A().bar() } diff --git a/idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt b/idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt index 328316b07ef..13f8d06f27a 100644 --- a/idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt +++ b/idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt @@ -9,6 +9,8 @@ class A { } fun main(args: Array) { + A() + //Breakpoint! A().bar } diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTest.java b/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTest.java index 92ed4cf7664..695ef09e8c5 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTest.java +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTest.java @@ -220,8 +220,8 @@ public class KotlinJpsBuildTest extends AbstractKotlinJpsBuildTestCase { // Check that outputs are located properly File facadeWithA = findFileInOutputDir(findModule("module1"), "test/TestPackage.class"); File facadeWithB = findFileInOutputDir(findModule("module2"), "test/TestPackage.class"); - assertSameElements(getMethodsOfClass(facadeWithA), "a", "getA"); - assertSameElements(getMethodsOfClass(facadeWithB), "b", "getB", "setB"); + assertSameElements(getMethodsOfClass(facadeWithA), "", "a", "getA"); + assertSameElements(getMethodsOfClass(facadeWithB), "", "b", "getB", "setB"); checkPackageDeletedFromOutputWhen(Operation.CHANGE, "module1", "module1/src/a.kt", "test.TestPackage"); checkPackageDeletedFromOutputWhen(Operation.CHANGE, "module2", "module2/src/b.kt", "test.TestPackage"); diff --git a/jps-plugin/testData/general/CircularDependenciesSamePackage/module1/src/a.kt b/jps-plugin/testData/general/CircularDependenciesSamePackage/module1/src/a.kt index 4987d3f36ec..8311da66012 100644 --- a/jps-plugin/testData/general/CircularDependenciesSamePackage/module1/src/a.kt +++ b/jps-plugin/testData/general/CircularDependenciesSamePackage/module1/src/a.kt @@ -4,4 +4,4 @@ fun a() { } -val a = "" \ No newline at end of file +val a = "" diff --git a/jps-plugin/testData/general/CircularDependenciesSamePackage/module2/src/b.kt b/jps-plugin/testData/general/CircularDependenciesSamePackage/module2/src/b.kt index 1dcef1df913..b04c387135d 100644 --- a/jps-plugin/testData/general/CircularDependenciesSamePackage/module2/src/b.kt +++ b/jps-plugin/testData/general/CircularDependenciesSamePackage/module2/src/b.kt @@ -4,4 +4,4 @@ fun b() { } -var b = "" \ No newline at end of file +var b = b() From 461cce103b175d7518caa058a256282559111044 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 6 Jun 2014 17:11:45 +0400 Subject: [PATCH 07/38] Support references to top level and member properties in JVM codegen #KT-1183 In Progress --- .../jet/codegen/ExpressionCodegen.java | 56 +++++++++++++--- .../lang/resolve/java/AsmTypeConstants.java | 14 +++- .../property/accessViaSubclass.kt | 9 +++ .../callableReference/property/delegated.kt | 22 +++++++ .../property/delegatedMutable.kt | 22 +++++++ .../property/javaBeanConvention.kt | 14 ++++ .../property/localClassVar.kt | 9 +++ .../property/overriddenInSubclass.kt | 9 +++ .../property/simpleMember.kt | 9 +++ .../property/simpleMutableMember.kt | 16 +++++ .../property/simpleMutableTopLevel.kt | 12 ++++ .../property/simpleTopLevel.kt | 10 +++ ...lackBoxWithStdlibCodegenTestGenerated.java | 66 ++++++++++++++++++- .../reflect/jvm/internal/KCallableImpl.kt | 21 ++++++ .../jvm/internal/KMemberPropertyImpl.kt | 42 ++++++++++++ .../reflect/jvm/internal/KPropertyImpl.kt | 26 ++++++++ .../jvm/internal/KTopLevelPropertyImpl.kt | 42 ++++++++++++ .../reflect/jvm/internal/KVariableImpl.kt | 26 ++++++++ .../src/kotlin/reflect/jvm/internal/util.kt | 44 +++++++++++++ 19 files changed, 457 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 8e9f9862f95..401b5687db2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -49,6 +49,7 @@ import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant; import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; +import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor; import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature; import org.jetbrains.jet.lang.resolve.name.Name; @@ -2410,19 +2411,56 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) { - // TODO: properties + ResolvedCall resolvedCall = resolvedCall(expression.getCallableReference()); FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); - assert functionDescriptor != null : "Callable reference is not resolved to descriptor: " + expression.getText(); + if (functionDescriptor != null) { + CallableReferenceGenerationStrategy strategy = new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall); + ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, context, + KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER, + this, strategy, getParentCodegen()); + closureCodegen.gen(); + return closureCodegen.putInstanceOnStack(v, this); + } - CallableReferenceGenerationStrategy strategy = - new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall(expression.getCallableReference())); - ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, context, - KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER, - this, strategy, getParentCodegen()); + VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); + if (variableDescriptor != null) { + VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor(); - closureCodegen.gen(); + String reflectionFieldOwner; + Type propertyType; + Type ownerType; + String reflectionFieldName; - return closureCodegen.putInstanceOnStack(v, this); + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + if (containingDeclaration instanceof PackageFragmentDescriptor) { + reflectionFieldOwner = + PackageClassUtils.getPackageClassInternalName(((PackageFragmentDescriptor) containingDeclaration).getFqName()); + + propertyType = descriptor.isVar() ? K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE : K_TOP_LEVEL_PROPERTY_IMPL_TYPE; + ownerType = K_PACKAGE_IMPL_TYPE; + reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME; + } + else if (containingDeclaration instanceof ClassDescriptor) { + reflectionFieldOwner = typeMapper.mapClass((ClassDescriptor) containingDeclaration).getInternalName(); + propertyType = descriptor.isVar() ? K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE : K_MEMBER_PROPERTY_IMPL_TYPE; + ownerType = K_CLASS_IMPL_TYPE; + reflectionFieldName = JvmAbi.KOTLIN_CLASS_FIELD_NAME; + } + else { + throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration); + } + + v.anew(propertyType); + v.dup(); + v.visitLdcInsn(descriptor.getName().asString()); + v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor()); + + v.invokespecial(propertyType.getInternalName(), "", + Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType), false); + return StackValue.onStack(propertyType); + } + + throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); } private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index d9a1f950fcc..4fe57bdf616 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -38,11 +38,21 @@ public class AsmTypeConstants { public static final Type PROPERTY_METADATA_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadata"); public static final Type PROPERTY_METADATA_IMPL_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadataImpl"); - public static final Type K_CLASS_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KClassImpl"); - public static final Type K_PACKAGE_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KPackageImpl"); + public static final Type K_CLASS_IMPL_TYPE = reflectInternal("KClassImpl"); + public static final Type K_PACKAGE_IMPL_TYPE = reflectInternal("KPackageImpl"); + public static final Type K_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KTopLevelPropertyImpl"); + public static final Type K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelPropertyImpl"); + public static final Type K_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMemberPropertyImpl"); + public static final Type K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMutableMemberPropertyImpl"); public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef"); + @NotNull + private static Type reflectInternal(@NotNull String className) { + return Type.getObjectType("kotlin/reflect/jvm/internal/" + className); + } + + @NotNull public static Type getType(@NotNull Class javaClass) { Type type = TYPES_MAP.get(javaClass); if (type == null) { diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt new file mode 100644 index 00000000000..eb2a0728db2 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt @@ -0,0 +1,9 @@ +abstract class Base { + val result = "OK" +} + +class Derived : Base() + +fun box(): String { + return (Base::result).get(Derived()) +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt new file mode 100644 index 00000000000..5c52e97b42a --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt @@ -0,0 +1,22 @@ +val four: Int by NumberDecrypter + +class A { + val two: Int by NumberDecrypter +} + +object NumberDecrypter { + fun get(instance: Any?, data: PropertyMetadata) = when (data.name) { + "four" -> 4 + "two" -> 2 + else -> throw AssertionError() + } +} + +fun box(): String { + val x = ::four.get() + if (x != 4) return "Fail x: $x" + val a = A() + val y = A::two.get(a) + if (y != 2) return "Fail y: $y" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt new file mode 100644 index 00000000000..e7a364cb432 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt @@ -0,0 +1,22 @@ +var result: String by Delegate + +object Delegate { + var value = "lol" + + fun get(instance: Any?, data: PropertyMetadata): String { + return value + } + + fun set(instance: Any?, data: PropertyMetadata, newValue: String) { + value = newValue + } +} + +fun box(): String { + val f = ::result + if (f.get() != "lol") return "Fail 1: {$f.get()}" + Delegate.value = "rofl" + if (f.get() != "rofl") return "Fail 2: {$f.get()}" + f.set("OK") + return f.get() +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt new file mode 100644 index 00000000000..0030d8026c3 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt @@ -0,0 +1,14 @@ +// Name of the getter should be 'getaBcde' according to JavaBean conventions +var aBcde: Int = 239 + +fun box(): String { + val x = (::aBcde).get() + if (x != 239) return "Fail x: $x" + + (::aBcde).set(42) + + val y = (::aBcde).get() + if (y != 42) return "Fail y: $y" + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt new file mode 100644 index 00000000000..fd45085df67 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt @@ -0,0 +1,9 @@ +fun box(): String { + class Local { + var result = "Fail" + } + + val l = Local() + (Local::result).set(l, "OK") + return (Local::result).get(l) +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt new file mode 100644 index 00000000000..d892efcba29 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt @@ -0,0 +1,9 @@ +open class Base { + open val foo = "Base" +} + +class Derived : Base() { + override val foo = "OK" +} + +fun box() = (Base::foo).get(Derived()) diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt new file mode 100644 index 00000000000..39bf36a0707 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt @@ -0,0 +1,9 @@ +class A(val x: Int) + +fun box(): String { + val p = A::x + if (p.get(A(42)) != 42) return "Fail 1" + if (p.get(A(-1)) != -1) return "Fail 2" + if (p.name != "x") return "Fail 3" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt new file mode 100644 index 00000000000..a187f252008 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt @@ -0,0 +1,16 @@ +data class Box(var value: String) + +fun box(): String { + val o = Box("lorem") + val prop = Box::value + + if (prop.get(o) != "lorem") return "Fail 1: ${prop[o]}" + prop.set(o, "ipsum") + if (prop.get(o) != "ipsum") return "Fail 2: ${prop[o]}" + if (o.value != "ipsum") return "Fail 3: ${o.value}" + o.value = "dolor" + if (prop.get(o) != "dolor") return "Fail 4: ${prop.get(o)}" + if ("$o" != "Box(value=dolor)") return "Fail 5: $o" + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt new file mode 100644 index 00000000000..46abcebe5f9 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt @@ -0,0 +1,12 @@ +data class Box(val value: String) + +var pr = Box("first") + +fun box(): String { + val property = ::pr + if (property.get() != Box("first")) return "Fail value: ${property.get()}" + if (property.name != "pr") return "Fail name: ${property.name}" + property.set(Box("second")) + if (property.get().value != "second") return "Fail value 2: ${property.get()}" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt new file mode 100644 index 00000000000..818327da26f --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt @@ -0,0 +1,10 @@ +data class Box(val value: String) + +val foo = Box("lol") + +fun box(): String { + val property = ::foo + if (property.get() != Box("lol")) return "Fail value: ${property.get()}" + if (property.name != "foo") return "Fail name: ${property.name}" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 840c767b4fd..547428cc25d 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -99,7 +99,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } @TestMetadata("compiler/testData/codegen/boxWithStdlib/callableReference") - @InnerTestClasses({CallableReference.Function.class}) + @InnerTestClasses({CallableReference.Function.class, CallableReference.Property.class}) public static class CallableReference extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInCallableReference() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/callableReference"), Pattern.compile("^(.+)\\.kt$"), true); @@ -418,10 +418,74 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property") + public static class Property extends AbstractBlackBoxCodegenTest { + @TestMetadata("accessViaSubclass.kt") + public void testAccessViaSubclass() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt"); + } + + public void testAllFilesPresentInProperty() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/callableReference/property"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("delegated.kt") + public void testDelegated() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt"); + } + + @TestMetadata("delegatedMutable.kt") + public void testDelegatedMutable() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt"); + } + + @TestMetadata("javaBeanConvention.kt") + public void testJavaBeanConvention() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt"); + } + + @TestMetadata("localClassVar.kt") + public void testLocalClassVar() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt"); + } + + @TestMetadata("overriddenInSubclass.kt") + public void testOverriddenInSubclass() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt"); + } + + @TestMetadata("simpleExtension.kt") + public void testSimpleExtension() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleExtension.kt"); + } + + @TestMetadata("simpleMember.kt") + public void testSimpleMember() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt"); + } + + @TestMetadata("simpleMutableMember.kt") + public void testSimpleMutableMember() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt"); + } + + @TestMetadata("simpleMutableTopLevel.kt") + public void testSimpleMutableTopLevel() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt"); + } + + @TestMetadata("simpleTopLevel.kt") + public void testSimpleTopLevel() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt"); + } + + } + public static Test innerSuite() { TestSuite suite = new TestSuite("CallableReference"); suite.addTestSuite(CallableReference.class); suite.addTest(Function.innerSuite()); + suite.addTestSuite(Property.class); return suite; } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt new file mode 100644 index 00000000000..cd3b87eabe9 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +abstract class KCallableImpl( + public override val name: String +) : KCallable diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt new file mode 100644 index 00000000000..38f3348982b --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +import java.lang.reflect.Method + +open class KMemberPropertyImpl( + name: String, + protected val owner: KClassImpl +) : KMemberProperty, KPropertyImpl(name) { + // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields + protected val getter: Method = owner.jClass.getMethod(getterName(name)) + + override fun get(receiver: T): R { + return getter(receiver) as R + } +} + +class KMutableMemberPropertyImpl( + name: String, + owner: KClassImpl +) : KMutableMemberProperty, KMemberPropertyImpl(name, owner) { + private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) + + override fun set(receiver: T, value: R) { + setter.invoke(receiver, value) + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt new file mode 100644 index 00000000000..8dbf08339a5 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +abstract class KPropertyImpl( + name: String +) : KProperty, KCallableImpl(name) + + +abstract class KMutablePropertyImpl( + name: String +) : KMutableProperty, KPropertyImpl(name) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt new file mode 100644 index 00000000000..b386d0c1a6a --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +import java.lang.reflect.Method + +open class KTopLevelPropertyImpl( + name: String, + protected val owner: KPackageImpl +) : KTopLevelProperty, KVariableImpl(name) { + // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields + protected val getter: Method = owner.jClass.getMethod(getterName(name)) + + override fun get(): R { + return getter(null) as R + } +} + +class KMutableTopLevelPropertyImpl( + name: String, + owner: KPackageImpl +) : KMutableTopLevelProperty, KTopLevelPropertyImpl(name, owner) { + private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) + + override fun set(value: R) { + setter.invoke(null, value) + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt new file mode 100644 index 00000000000..9932b7559a5 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +abstract class KVariableImpl( + name: String +) : KVariable, KPropertyImpl(name) + + +abstract class KMutableVariableImpl( + name: String +) : KMutableVariable, KVariableImpl(name) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt new file mode 100644 index 00000000000..ffaf0281354 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +// TODO: use stdlib? +suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") +private fun String.capitalizeWithJavaBeanConvention(): String { + // The code is a bit crooked because otherwise there are overload resolution ambiguities caused by the fact + // that we compile it with the built-ins both in source and as a compiled library + val l = length + if (l > 1 && Character.isUpperCase(get(1))) return this + val first = get(0) + this as java.lang.String + return "" + Character.toUpperCase(first) + substring(1, l) +} + +private fun getterName(propertyName: String): String = "get" + propertyName.capitalizeWithJavaBeanConvention() +private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention() + + +private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject") + +// TODO +fun kotlinClass(jClass: Class): KClassImpl { + if (K_OBJECT_CLASS.isAssignableFrom(jClass)) { + val field = jClass.getDeclaredField("\$kotlinClass") + return field.get(null) as KClassImpl + } + throw UnsupportedOperationException("Unsupported class: $jClass") +} From 5ab83aad8a8563bf3e546a3febd2f5580d50517a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 27 May 2014 21:28:06 +0400 Subject: [PATCH 08/38] Support references to extension properties in JVM codegen #KT-1183 In Progress --- .../org/jetbrains/jet/codegen/AsmUtil.java | 8 ++++ .../jet/codegen/ExpressionCodegen.java | 22 ++++++++-- .../codegen/intrinsics/JavaClassFunction.java | 15 ++----- .../lang/resolve/java/AsmTypeConstants.java | 2 + .../property/simpleExtension.kt | 12 +++++ .../property/simpleMutableExtension.kt | 18 ++++++++ .../PropertyReference.A.kt | 6 +++ .../PropertyReference.B.kt | 14 ++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 5 +++ ...bstractCompileKotlinAgainstKotlinTest.java | 5 ++- ...mpileKotlinAgainstKotlinTestGenerated.java | 5 +++ .../jvm/internal/KExtensionPropertyImpl.kt | 44 +++++++++++++++++++ 12 files changed, 140 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleExtension.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableExtension.kt create mode 100644 compiler/testData/compileKotlinAgainstKotlin/PropertyReference.A.kt create mode 100644 compiler/testData/compileKotlinAgainstKotlin/PropertyReference.B.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index badbff196fc..ce05e888687 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -785,4 +785,12 @@ public class AsmUtil { return PackagePartClassUtils.getPackagePartInternalName(containingFile); } + public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) { + if (isPrimitive(type)) { + v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;"); + } + else { + v.aconst(type); + } + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 401b5687db2..04865fb6c1a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2426,6 +2426,8 @@ public class ExpressionCodegen extends JetVisitor implem if (variableDescriptor != null) { VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor(); + ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); + String reflectionFieldOwner; Type propertyType; Type ownerType; @@ -2436,7 +2438,13 @@ public class ExpressionCodegen extends JetVisitor implem reflectionFieldOwner = PackageClassUtils.getPackageClassInternalName(((PackageFragmentDescriptor) containingDeclaration).getFqName()); - propertyType = descriptor.isVar() ? K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE : K_TOP_LEVEL_PROPERTY_IMPL_TYPE; + if (receiverParameter != null) { + propertyType = descriptor.isVar() ? K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE : K_EXTENSION_PROPERTY_IMPL_TYPE; + } + else { + propertyType = descriptor.isVar() ? K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE : K_TOP_LEVEL_PROPERTY_IMPL_TYPE; + } + ownerType = K_PACKAGE_IMPL_TYPE; reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME; } @@ -2455,8 +2463,16 @@ public class ExpressionCodegen extends JetVisitor implem v.visitLdcInsn(descriptor.getName().asString()); v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor()); - v.invokespecial(propertyType.getInternalName(), "", - Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType), false); + String constructorDesc; + if (receiverParameter != null) { + putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter)); + constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType, getType(Class.class)); + } + else { + constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType); + } + + v.invokespecial(propertyType.getInternalName(), "", constructorDesc, false); return StackValue.onStack(propertyType); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/JavaClassFunction.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/JavaClassFunction.java index d1b3b660cb6..cc2c8c52be2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/JavaClassFunction.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/JavaClassFunction.java @@ -19,8 +19,6 @@ package org.jetbrains.jet.codegen.intrinsics; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetCallExpression; @@ -28,11 +26,12 @@ import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import java.util.List; -import static org.jetbrains.jet.codegen.AsmUtil.boxType; -import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive; +import static org.jetbrains.jet.codegen.AsmUtil.putJavaLangClassInstance; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType; public class JavaClassFunction extends IntrinsicMethod { @@ -51,13 +50,7 @@ public class JavaClassFunction extends IntrinsicMethod { assert resolvedCall != null; JetType returnType = resolvedCall.getResultingDescriptor().getReturnType(); assert returnType != null; - Type type = codegen.getState().getTypeMapper().mapType(returnType.getArguments().get(0).getType()); - if (isPrimitive(type)) { - v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;"); - } - else { - v.aconst(type); - } + putJavaLangClassInstance(v, codegen.getState().getTypeMapper().mapType(returnType.getArguments().get(0).getType())); return getType(Class.class); } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index 4fe57bdf616..5ec815ea374 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -44,6 +44,8 @@ public class AsmTypeConstants { public static final Type K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelPropertyImpl"); public static final Type K_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMemberPropertyImpl"); public static final Type K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMutableMemberPropertyImpl"); + public static final Type K_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KExtensionPropertyImpl"); + public static final Type K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KMutableExtensionPropertyImpl"); public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef"); diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleExtension.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleExtension.kt new file mode 100644 index 00000000000..7e6b5c92df1 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleExtension.kt @@ -0,0 +1,12 @@ +val String.id: String + get() = this + +fun box(): String { + val pr = String::id + + if (pr["123"] != "123") return "Fail value: ${pr["123"]}" + + if (pr.name != "id") return "Fail name: ${pr.name}" + + return pr.get("OK") +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableExtension.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableExtension.kt new file mode 100644 index 00000000000..0d5c562bcff --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableExtension.kt @@ -0,0 +1,18 @@ +var storage = 0 + +var Int.foo: Int + get() { + return this + storage + } + set(value) { + storage = this + value + } + +fun box(): String { + val pr = Int::foo + if (pr.get(42) != 42) return "Fail 1: ${pr[42]}" + pr.set(200, 39) + if (pr.get(-239) != 0) return "Fail 2: ${pr[-239]}" + if (storage != 239) return "Fail 3: $storage" + return "OK" +} diff --git a/compiler/testData/compileKotlinAgainstKotlin/PropertyReference.A.kt b/compiler/testData/compileKotlinAgainstKotlin/PropertyReference.A.kt new file mode 100644 index 00000000000..ea68a0dea53 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/PropertyReference.A.kt @@ -0,0 +1,6 @@ +package a + +public var topLevel: Int = 42 + +public val String.extension: Long + get() = length.toLong() diff --git a/compiler/testData/compileKotlinAgainstKotlin/PropertyReference.B.kt b/compiler/testData/compileKotlinAgainstKotlin/PropertyReference.B.kt new file mode 100644 index 00000000000..5a9e82e1b29 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/PropertyReference.B.kt @@ -0,0 +1,14 @@ +import a.* + +fun main(args: Array) { + val f = ::topLevel + val x1 = f.get() + if (x1 != 42) throw AssertionError("Fail x1: $x1") + f.set(239) + val x2 = f.get() + if (x2 != 239) throw AssertionError("Fail x2: $x2") + + val g = String::extension + val y1 = g.get("abcde") + if (y1 != 5L) throw AssertionError("Fail y1: $y1") +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 547428cc25d..257d4fb5d7f 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -464,6 +464,11 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt"); } + @TestMetadata("simpleMutableExtension.kt") + public void testSimpleMutableExtension() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableExtension.kt"); + } + @TestMetadata("simpleMutableMember.kt") public void testSimpleMutableMember() throws Exception { doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt"); diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstKotlinTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstKotlinTest.java index 899551591e1..e5b95bc318d 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstKotlinTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstKotlinTest.java @@ -28,6 +28,7 @@ import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.GenerationUtils; import org.jetbrains.jet.codegen.InlineTestUtil; +import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.jet.config.CompilerConfiguration; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; @@ -108,7 +109,7 @@ public abstract class AbstractCompileKotlinAgainstKotlinTest extends TestCaseWit private void invokeMain() throws Exception { URLClassLoader classLoader = new URLClassLoader( - new URL[]{ aDir.toURI().toURL(), bDir.toURI().toURL() }, + new URL[]{ aDir.toURI().toURL(), bDir.toURI().toURL(), ForTestCompileRuntime.runtimeJarForTests().toURI().toURL() }, AbstractCompileKotlinAgainstKotlinTest.class.getClassLoader() ); Class clazz = classLoader.loadClass(PackageClassUtils.getPackageClassName(FqName.ROOT)); @@ -118,7 +119,7 @@ public abstract class AbstractCompileKotlinAgainstKotlinTest extends TestCaseWit private void invokeBox() throws Exception { URLClassLoader classLoader = new URLClassLoader( - new URL[]{ bDir.toURI().toURL(), aDir.toURI().toURL() }, + new URL[]{ bDir.toURI().toURL(), aDir.toURI().toURL(), ForTestCompileRuntime.runtimeJarForTests().toURI().toURL() }, AbstractCompileKotlinAgainstKotlinTest.class.getClassLoader() ); Class clazz = classLoader.loadClass(PackageClassUtils.getPackageClassName(FqName.ROOT)); diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java index fcece966531..aa7a31d4f0c 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java @@ -106,6 +106,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl doTest("compiler/testData/compileKotlinAgainstKotlin/PlatformNames.A.kt"); } + @TestMetadata("PropertyReference.A.kt") + public void testPropertyReference() throws Exception { + doTest("compiler/testData/compileKotlinAgainstKotlin/PropertyReference.A.kt"); + } + @TestMetadata("Simple.A.kt") public void testSimple() throws Exception { doTest("compiler/testData/compileKotlinAgainstKotlin/Simple.A.kt"); diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt new file mode 100644 index 00000000000..0850703dad6 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +import java.lang.reflect.Method + +open class KExtensionPropertyImpl( + name: String, + protected val owner: KPackageImpl, + protected val receiverClass: Class +) : KExtensionProperty, KPropertyImpl(name) { + // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields + protected val getter: Method = owner.jClass.getMethod(getterName(name), receiverClass) + + override fun get(receiver: T): R { + return getter(null, receiver) as R + } +} + +class KMutableExtensionPropertyImpl( + name: String, + owner: KPackageImpl, + receiverClass: Class +) : KMutableExtensionProperty, KExtensionPropertyImpl(name, owner, receiverClass) { + private val setter = owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!) + + override fun set(receiver: T, value: R) { + setter.invoke(null, receiver, value) + } +} From a8e1de48b809bb17dffbc5ba236515a056bcf5cf Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 30 May 2014 21:21:03 +0400 Subject: [PATCH 09/38] Support :: references to Java instance fields in codegen #KT-1183 In Progress --- .../jet/codegen/ExpressionCodegen.java | 12 ++++++- .../callableReference/publicFinalField.java | 3 ++ .../callableReference/publicFinalField.kt | 1 + .../callableReference/publicMutableField.java | 3 ++ .../callableReference/publicMutableField.kt | 11 +++++++ ...ackBoxAgainstJavaCodegenTestGenerated.java | 10 ++++++ .../kotlin/reflect/jvm/internal/KClassImpl.kt | 17 +++++++++- .../jvm/internal/KMemberPropertyImpl.kt | 33 ++++++++++++++++--- .../src/kotlin/reflect/jvm/internal/util.kt | 17 ++++++++-- 9 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.java create mode 100644 compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.kt create mode 100644 compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.java create mode 100644 compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 04865fb6c1a..4dedb68bf2b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -50,6 +50,7 @@ import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; +import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor; import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature; import org.jetbrains.jet.lang.resolve.name.Name; @@ -2461,7 +2462,16 @@ public class ExpressionCodegen extends JetVisitor implem v.anew(propertyType); v.dup(); v.visitLdcInsn(descriptor.getName().asString()); - v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor()); + + if (containingDeclaration instanceof JavaClassDescriptor) { + v.aconst(Type.getObjectType(reflectionFieldOwner)); + v.invokestatic("kotlin/reflect/jvm/internal/InternalPackage", "foreignKotlinClass", + Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false); + } + else { + // TODO: built-in classes + v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor()); + } String constructorDesc; if (receiverParameter != null) { diff --git a/compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.java b/compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.java new file mode 100644 index 00000000000..48056198e02 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.java @@ -0,0 +1,3 @@ +public class publicFinalField { + public final String field = "OK"; +} diff --git a/compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.kt b/compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.kt new file mode 100644 index 00000000000..7cc41f66006 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.kt @@ -0,0 +1 @@ +fun box() = (publicFinalField::field).get(publicFinalField()) diff --git a/compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.java b/compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.java new file mode 100644 index 00000000000..b675de28fdb --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.java @@ -0,0 +1,3 @@ +public class publicMutableField { + public int field = 239; +} diff --git a/compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.kt b/compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.kt new file mode 100644 index 00000000000..563afaaf69b --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.kt @@ -0,0 +1,11 @@ +import publicMutableField as A + +fun box(): String { + val a = A() + val f = A::field + if (f.get(a) != 239) return "Fail 1: ${f.get(a)}" + f[a] = 42 + if (f.get(a) != 42) return "Fail 2: ${f.get(a)}" + if (f.get(a) != 42) return "Fail 2: ${f.get(a)}" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java index ba89e324887..22a8556dee2 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java @@ -86,6 +86,16 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/callableReference/constructor.kt"); } + @TestMetadata("publicFinalField.kt") + public void testPublicFinalField() throws Exception { + doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.kt"); + } + + @TestMetadata("publicMutableField.kt") + public void testPublicMutableField() throws Exception { + doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.kt"); + } + } @TestMetadata("compiler/testData/codegen/boxAgainstJava/constructor") diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 084a36d0ed1..e191d9878b6 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -16,6 +16,21 @@ package kotlin.reflect.jvm.internal +enum class KClassOrigin { + BUILT_IN + KOTLIN + FOREIGN +} + class KClassImpl( val jClass: Class -) : KClass +) : KClass { + val origin: KClassOrigin = + if (K_OBJECT_CLASS.isAssignableFrom(jClass)) { + KClassOrigin.KOTLIN + } + else { + KClassOrigin.FOREIGN + // TODO: built-in classes + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 38f3348982b..2cee6e4e2c1 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -16,17 +16,32 @@ package kotlin.reflect.jvm.internal +import java.lang.reflect.Field import java.lang.reflect.Method open class KMemberPropertyImpl( name: String, protected val owner: KClassImpl ) : KMemberProperty, KPropertyImpl(name) { - // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields - protected val getter: Method = owner.jClass.getMethod(getterName(name)) + protected val field: Field? = + if (owner.origin == KClassOrigin.FOREIGN) { + owner.jClass.getField(name) + } + else null + // TODO: extract, make lazy (weak?), use our descriptors knowledge + protected val getter: Method? = + if (owner.origin == KClassOrigin.KOTLIN) { + owner.jClass.getMethod(getterName(name)) + } + else null + + // TODO: built-in classes override fun get(receiver: T): R { - return getter(receiver) as R + if (getter != null) { + return getter!!(receiver) as R + } + return field!!.get(receiver) as R } } @@ -34,9 +49,17 @@ class KMutableMemberPropertyImpl( name: String, owner: KClassImpl ) : KMutableMemberProperty, KMemberPropertyImpl(name, owner) { - private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) + private val setter: Method? = + if (owner.origin == KClassOrigin.KOTLIN) { + owner.jClass.getMethod(setterName(name), getter!!.getReturnType()!!) + } + else null override fun set(receiver: T, value: R) { - setter.invoke(receiver, value) + if (setter != null) { + setter!!(receiver, value) + return + } + field!!.set(receiver, value) } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt index ffaf0281354..b8a5c6368f5 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -16,6 +16,8 @@ package kotlin.reflect.jvm.internal +import java.util.concurrent.ConcurrentHashMap + // TODO: use stdlib? suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") private fun String.capitalizeWithJavaBeanConvention(): String { @@ -32,13 +34,24 @@ private fun getterName(propertyName: String): String = "get" + propertyName.capi private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention() +// TODO: should use weak references +private val foreignKClasses: MutableMap, KClassImpl<*>> = ConcurrentHashMap() + +fun foreignKotlinClass(jClass: Class): KClassImpl { + val cached = foreignKClasses[jClass] as? KClassImpl + if (cached != null) return cached + val result = KClassImpl(jClass) + foreignKClasses.put(jClass, result) + return result +} + private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject") -// TODO fun kotlinClass(jClass: Class): KClassImpl { if (K_OBJECT_CLASS.isAssignableFrom(jClass)) { val field = jClass.getDeclaredField("\$kotlinClass") return field.get(null) as KClassImpl } - throw UnsupportedOperationException("Unsupported class: $jClass") + // TODO: built-in classes + return foreignKotlinClass(jClass) } From 1275c84f92f65b162e729017746792fec0d7925e Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 5 Jun 2014 16:51:25 +0400 Subject: [PATCH 10/38] Fail with IllegalAccessException on :: reference to private property Instead of mysterious NoSuchMethodException --- .../callableReference/property/privateClassVal.kt | 15 +++++++++++++++ .../BlackBoxWithStdlibCodegenTestGenerated.java | 5 +++++ .../reflect/jvm/internal/KMemberPropertyImpl.kt | 4 ++-- .../src/kotlin/reflect/jvm/internal/util.kt | 12 ++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt new file mode 100644 index 00000000000..eaafec45535 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt @@ -0,0 +1,15 @@ +class Result { + private val value = "OK" + + fun ref(): KMemberProperty = ::value +} + +fun box(): String { + val p = Result().ref() + try { + p.get(Result()) + return "Fail: private property is accessible by default" + } catch(e: IllegalAccessException) { } + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 257d4fb5d7f..9080f40c293 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -454,6 +454,11 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt"); } + @TestMetadata("privateClassVal.kt") + public void testPrivateClassVal() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt"); + } + @TestMetadata("simpleExtension.kt") public void testSimpleExtension() throws Exception { doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleExtension.kt"); diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 2cee6e4e2c1..482a274f0c6 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -32,7 +32,7 @@ open class KMemberPropertyImpl( // TODO: extract, make lazy (weak?), use our descriptors knowledge protected val getter: Method? = if (owner.origin == KClassOrigin.KOTLIN) { - owner.jClass.getMethod(getterName(name)) + owner.jClass.getMaybeDeclaredMethod(getterName(name)) } else null @@ -51,7 +51,7 @@ class KMutableMemberPropertyImpl( ) : KMutableMemberProperty, KMemberPropertyImpl(name, owner) { private val setter: Method? = if (owner.origin == KClassOrigin.KOTLIN) { - owner.jClass.getMethod(setterName(name), getter!!.getReturnType()!!) + owner.jClass.getMaybeDeclaredMethod(setterName(name), getter!!.getReturnType()!!) } else null diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt index b8a5c6368f5..b1ed0ac560a 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -16,6 +16,7 @@ package kotlin.reflect.jvm.internal +import java.lang.reflect.Method import java.util.concurrent.ConcurrentHashMap // TODO: use stdlib? @@ -34,6 +35,17 @@ private fun getterName(propertyName: String): String = "get" + propertyName.capi private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention() +private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: Class<*>): Method { + try { + return getMethod(name, *parameterTypes) + } + catch (e: NoSuchMethodException) { + // This is needed to support private methods + return getDeclaredMethod(name, *parameterTypes) + } +} + + // TODO: should use weak references private val foreignKClasses: MutableMap, KClassImpl<*>> = ConcurrentHashMap() From e7f19c531aa98892181353ab165457f58814dee6 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 5 Jun 2014 19:15:09 +0400 Subject: [PATCH 11/38] Support 'accessible' for reflected properties on JVM Calls Java reflection's isAccessible/setAccessible --- .../property/privateClassVal.kt | 14 +++++- .../property/privateClassVar.kt | 29 +++++++++++ .../property/protectedClassVar.kt | 28 +++++++++++ .../property/publicClassValAccessible.kt | 12 +++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 15 ++++++ .../jvm/internal/KMemberPropertyImpl.kt | 6 +-- .../src/kotlin/reflect/jvm/properties.kt | 50 +++++++++++++++++++ 7 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/publicClassValAccessible.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt index eaafec45535..21971bd98a0 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.jvm.accessible + class Result { private val value = "OK" @@ -11,5 +13,15 @@ fun box(): String { return "Fail: private property is accessible by default" } catch(e: IllegalAccessException) { } - return "OK" + p.accessible = true + + val r = p.get(Result()) + + p.accessible = false + try { + p.get(Result()) + return "Fail: setAccessible(false) had no effect" + } catch(e: IllegalAccessException) { } + + return r } diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt new file mode 100644 index 00000000000..25d98f9e51a --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt @@ -0,0 +1,29 @@ +import kotlin.reflect.jvm.accessible + +class A { + private var value = 0 + + fun ref(): KMutableMemberProperty = ::value +} + +fun box(): String { + val a = A() + val p = a.ref() + try { + p.set(a, 1) + return "Fail: private property is accessible by default" + } catch(e: IllegalAccessException) { } + + p.accessible = true + + p.set(a, 2) + p.get(a) + + p.accessible = false + try { + p.set(a, 3) + return "Fail: setAccessible(false) had no effect" + } catch(e: IllegalAccessException) { } + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt new file mode 100644 index 00000000000..112038072a4 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt @@ -0,0 +1,28 @@ +import kotlin.reflect.jvm.accessible + +class A(param: String) { + protected var v: String = param + + fun ref() = ::v +} + +fun box(): String { + val a = A(":(") + val f = a.ref() + + try { + f.get(a) + return "Fail: protected property getter is accessible by default" + } catch (e: IllegalAccessException) { } + + try { + f.set(a, ":D") + return "Fail: protected property setter is accessible by default" + } catch (e: IllegalAccessException) { } + + f.accessible = true + + f.set(a, ":)") + + return if (f[a] != ":)") "Fail: ${f[a]}" else "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/publicClassValAccessible.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/publicClassValAccessible.kt new file mode 100644 index 00000000000..3fe95c7c7e0 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/publicClassValAccessible.kt @@ -0,0 +1,12 @@ +import kotlin.reflect.jvm.accessible + +class Result { + public val value: String = "OK" +} + +fun box(): String { + val p = Result::value + p.accessible = false + // setAccessible(false) should have no effect on the accessibility of a public reflection object + return p.get(Result()) +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 9080f40c293..cbdf3206a6a 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -459,6 +459,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt"); } + @TestMetadata("privateClassVar.kt") + public void testPrivateClassVar() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt"); + } + + @TestMetadata("protectedClassVar.kt") + public void testProtectedClassVar() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt"); + } + + @TestMetadata("publicClassValAccessible.kt") + public void testPublicClassValAccessible() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/publicClassValAccessible.kt"); + } + @TestMetadata("simpleExtension.kt") public void testSimpleExtension() throws Exception { doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleExtension.kt"); diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 482a274f0c6..86ad94691aa 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -23,14 +23,14 @@ open class KMemberPropertyImpl( name: String, protected val owner: KClassImpl ) : KMemberProperty, KPropertyImpl(name) { - protected val field: Field? = + val field: Field? = if (owner.origin == KClassOrigin.FOREIGN) { owner.jClass.getField(name) } else null // TODO: extract, make lazy (weak?), use our descriptors knowledge - protected val getter: Method? = + val getter: Method? = if (owner.origin == KClassOrigin.KOTLIN) { owner.jClass.getMaybeDeclaredMethod(getterName(name)) } @@ -49,7 +49,7 @@ class KMutableMemberPropertyImpl( name: String, owner: KClassImpl ) : KMutableMemberProperty, KMemberPropertyImpl(name, owner) { - private val setter: Method? = + val setter: Method? = if (owner.origin == KClassOrigin.KOTLIN) { owner.jClass.getMaybeDeclaredMethod(setterName(name), getter!!.getReturnType()!!) } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt new file mode 100644 index 00000000000..e7e4abdd452 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm + +import kotlin.reflect.jvm.internal.KMemberPropertyImpl +import kotlin.reflect.jvm.internal.KMutableMemberPropertyImpl + +public var KProperty.accessible: Boolean + get() { + return when (this) { + is KMutableMemberPropertyImpl<*, R> -> + field?.isAccessible() ?: true && + getter?.isAccessible() ?: true && + setter?.isAccessible() ?: true + is KMemberPropertyImpl<*, R> -> + field?.isAccessible() ?: true && + getter?.isAccessible() ?: true + else -> { + // Non-member properties always have public visibility on JVM, thus accessible has no effect on them + true + } + } + } + set(value) { + when (this) { + is KMutableMemberPropertyImpl<*, R> -> { + field?.setAccessible(value) + getter?.setAccessible(value) + setter?.setAccessible(value) + } + is KMemberPropertyImpl<*, R> -> { + field?.setAccessible(value) + getter?.setAccessible(value) + } + } + } From c17f515d062f66920748a50d8bdd4f299a22c91c Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 9 Jun 2014 16:31:30 +0400 Subject: [PATCH 12/38] Construct reflection objects via static factory methods JVM back-end now generates invocations of these methods instead of KClass/K*Property/... constructors for two reasons: 1. It occupies less space in the bytecode 2. We can (to some degree) alter the implementation of the factory methods without changing the ABI compatibility version --- .../org/jetbrains/jet/codegen/AsmUtil.java | 5 +++ .../jet/codegen/ExpressionCodegen.java | 40 +++++++++-------- .../codegen/ImplementationBodyCodegen.java | 4 +- .../jetbrains/jet/codegen/MemberCodegen.java | 13 +++--- .../jetbrains/jet/codegen/PackageCodegen.java | 12 ++++-- .../lang/resolve/java/AsmTypeConstants.java | 2 + .../kotlin/reflect/jvm/internal/factory.kt | 43 +++++++++++++++++++ 7 files changed, 87 insertions(+), 32 deletions(-) create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index ce05e888687..202053b1d23 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -154,6 +154,11 @@ public class AsmUtil { return Type.getType(internalName.substring(1)); } + @NotNull + public static Method method(@NotNull String name, @NotNull Type returnType, @NotNull Type... parameterTypes) { + return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes)); + } + public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { return (functionDescriptor.getModality() == Modality.ABSTRACT || isInterface(functionDescriptor.getContainingDeclaration())) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 4dedb68bf2b..92a0a2c1856 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2430,42 +2430,49 @@ public class ExpressionCodegen extends JetVisitor implem ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); String reflectionFieldOwner; - Type propertyType; Type ownerType; String reflectionFieldName; + Method factory; DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); if (containingDeclaration instanceof PackageFragmentDescriptor) { reflectionFieldOwner = PackageClassUtils.getPackageClassInternalName(((PackageFragmentDescriptor) containingDeclaration).getFqName()); - if (receiverParameter != null) { - propertyType = descriptor.isVar() ? K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE : K_EXTENSION_PROPERTY_IMPL_TYPE; - } - else { - propertyType = descriptor.isVar() ? K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE : K_TOP_LEVEL_PROPERTY_IMPL_TYPE; - } - ownerType = K_PACKAGE_IMPL_TYPE; reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME; + + if (receiverParameter != null) { + factory = descriptor.isVar() + ? method("mutableExtensionProperty", K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType, + getType(Class.class)) + : method("extensionProperty", K_EXTENSION_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType, + getType(Class.class)); + } + else { + factory = descriptor.isVar() + ? method("mutableTopLevelProperty", K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType) + : method("topLevelProperty", K_TOP_LEVEL_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType); + } } else if (containingDeclaration instanceof ClassDescriptor) { reflectionFieldOwner = typeMapper.mapClass((ClassDescriptor) containingDeclaration).getInternalName(); - propertyType = descriptor.isVar() ? K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE : K_MEMBER_PROPERTY_IMPL_TYPE; ownerType = K_CLASS_IMPL_TYPE; reflectionFieldName = JvmAbi.KOTLIN_CLASS_FIELD_NAME; + + factory = descriptor.isVar() + ? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType) + : method("memberProperty", K_MEMBER_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType); } else { throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration); } - v.anew(propertyType); - v.dup(); v.visitLdcInsn(descriptor.getName().asString()); if (containingDeclaration instanceof JavaClassDescriptor) { v.aconst(Type.getObjectType(reflectionFieldOwner)); - v.invokestatic("kotlin/reflect/jvm/internal/InternalPackage", "foreignKotlinClass", + v.invokestatic(REFLECTION_INTERNAL_PACKAGE, "foreignKotlinClass", Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false); } else { @@ -2473,17 +2480,12 @@ public class ExpressionCodegen extends JetVisitor implem v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor()); } - String constructorDesc; if (receiverParameter != null) { putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter)); - constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType, getType(Class.class)); - } - else { - constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType); } - v.invokespecial(propertyType.getInternalName(), "", constructorDesc, false); - return StackValue.onStack(propertyType); + v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factory.getName(), factory.getDescriptor(), false); + return StackValue.onStack(factory.getReturnType()); } throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index a125ab0f0f2..70456a08250 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -473,8 +473,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return; } - generateReflectionObjectField(state, classAsmType, v, K_CLASS_IMPL_TYPE, JvmAbi.KOTLIN_CLASS_FIELD_NAME, - createOrGetClInitCodegen().v); + generateReflectionObjectField(state, classAsmType, v, method("kClass", K_CLASS_IMPL_TYPE, getType(Class.class)), + JvmAbi.KOTLIN_CLASS_FIELD_NAME, createOrGetClInitCodegen().v); generatePropertyMetadataArrayFieldIfNeeded(classAsmType); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index 622b710fe57..910cd303da0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -43,6 +43,7 @@ import org.jetbrains.jet.storage.NotNullLazyValue; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; +import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.ArrayList; import java.util.Collections; @@ -320,21 +321,19 @@ public abstract class MemberCodegen", "(Ljava/lang/Class;)V", false); - v.putstatic(thisAsmType.getInternalName(), fieldName, kImplType.getDescriptor()); + v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factory.getName(), factory.getDescriptor(), false); + v.putstatic(thisAsmType.getInternalName(), fieldName, type); } protected void generatePropertyMetadataArrayFieldIfNeeded(@NotNull Type thisAsmType) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java index 24a8e07baf2..2356350d5fc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java @@ -57,12 +57,15 @@ import org.jetbrains.org.objectweb.asm.AnnotationVisitor; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; +import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.*; import static org.jetbrains.jet.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses; +import static org.jetbrains.jet.codegen.AsmUtil.method; import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.K_PACKAGE_IMPL_TYPE; +import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType; import static org.jetbrains.jet.lang.resolve.java.PackageClassUtils.getPackageClassFqName; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.*; import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; @@ -243,10 +246,11 @@ public class PackageCodegen { private void generateKotlinPackageReflectionField() { MethodVisitor mv = v.newMethod(NO_ORIGIN, ACC_STATIC, "", "()V", null, null); - MemberCodegen.generateReflectionObjectField(state, packageClassType, v, K_PACKAGE_IMPL_TYPE, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, - new InstructionAdapter(mv)); - mv.visitInsn(RETURN); - FunctionCodegen.endVisit(mv, "static initializer", null); + Method method = method("kPackage", K_PACKAGE_IMPL_TYPE, getType(Class.class)); + InstructionAdapter iv = new InstructionAdapter(mv); + MemberCodegen.generateReflectionObjectField(state, packageClassType, v, method, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, iv); + iv.areturn(Type.VOID_TYPE); + FunctionCodegen.endVisit(mv, "package facade static initializer", null); } private void writeKotlinPackageAnnotationIfNeeded(@NotNull JvmSerializationBindings bindings) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index 5ec815ea374..e1099d1dbc6 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -47,6 +47,8 @@ public class AsmTypeConstants { public static final Type K_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KExtensionPropertyImpl"); public static final Type K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KMutableExtensionPropertyImpl"); + public static final String REFLECTION_INTERNAL_PACKAGE = reflectInternal("InternalPackage").getInternalName(); + public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef"); @NotNull diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt new file mode 100644 index 00000000000..1979953a35c --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + + +fun kClass(jClass: Class): KClassImpl = + KClassImpl(jClass) + +fun kPackage(jClass: Class<*>): KPackageImpl = + KPackageImpl(jClass) + +fun topLevelProperty(name: String, owner: KPackageImpl): KTopLevelPropertyImpl = + KTopLevelPropertyImpl(name, owner) + +fun mutableTopLevelProperty(name: String, owner: KPackageImpl): KMutableTopLevelPropertyImpl = + KMutableTopLevelPropertyImpl(name, owner) + +fun extensionProperty(name: String, owner: KPackageImpl, receiver: Class): KExtensionPropertyImpl = + KExtensionPropertyImpl(name, owner, receiver) + +fun mutableExtensionProperty(name: String, owner: KPackageImpl, receiver: Class): KMutableExtensionPropertyImpl = + KMutableExtensionPropertyImpl(name, owner, receiver) + +fun memberProperty(name: String, owner: KClassImpl): KMemberPropertyImpl = + KMemberPropertyImpl(name, owner) + +fun mutableMemberProperty(name: String, owner: KClassImpl): KMutableMemberPropertyImpl = + KMutableMemberPropertyImpl(name, owner) + From 89d6f25fb63b73dfcbf2cd37ba0004b4a0155190 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 9 Jun 2014 17:52:10 +0400 Subject: [PATCH 13/38] Fix initialization order of KClass field and class object fields --- .../jet/codegen/ImplementationBodyCodegen.java | 8 ++++---- .../property/kClassInstanceIsInitializedFirst.kt | 11 +++++++++++ .../BlackBoxWithStdlibCodegenTestGenerated.java | 5 +++++ 3 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 70456a08250..9425d6e31f1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -208,6 +208,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { writeInnerClasses(); AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor, null); + + generateReflectionObjectFieldIfNeeded(); } @Override @@ -428,7 +430,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { @Override protected void generateSyntheticParts() { - generateStaticSyntheticFields(); + generatePropertyMetadataArrayFieldIfNeeded(classAsmType); generateFieldForSingleton(); @@ -465,7 +467,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { genClosureFields(context.closure, v, typeMapper); } - private void generateStaticSyntheticFields() { + private void generateReflectionObjectFieldIfNeeded() { if (isAnnotationClass(descriptor)) { // There's a bug in JDK 6 and 7 that prevents us from generating a static field in an annotation class: // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6857918 @@ -475,8 +477,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateReflectionObjectField(state, classAsmType, v, method("kClass", K_CLASS_IMPL_TYPE, getType(Class.class)), JvmAbi.KOTLIN_CLASS_FIELD_NAME, createOrGetClInitCodegen().v); - - generatePropertyMetadataArrayFieldIfNeeded(classAsmType); } private boolean isGenericToArrayPresent() { diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt new file mode 100644 index 00000000000..cc80b293bf7 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt @@ -0,0 +1,11 @@ +class A { + class object { + val ref: KMemberProperty = A::foo + } + + val foo: String = "OK" +} + +fun box(): String { + return A.ref.get(A()) +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index cbdf3206a6a..dc620d36cdf 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -444,6 +444,11 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt"); } + @TestMetadata("kClassInstanceIsInitializedFirst.kt") + public void testKClassInstanceIsInitializedFirst() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt"); + } + @TestMetadata("localClassVar.kt") public void testLocalClassVar() throws Exception { doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt"); From 58bc611e3a429ba7c9589b66cc9b6a5787a40c02 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 9 Jun 2014 21:24:27 +0400 Subject: [PATCH 14/38] Copy pcollections's HashPMap to kotlin/reflect/jvm/internal It will be used for caching KClass instances for foreign (Java) classes --- .../jet/parsing/JetCodeConformanceTest.java | 2 + .../jvm/internal/pcollections/ConsPStack.java | 210 ++++++++++++ .../jvm/internal/pcollections/HashPMap.java | 175 ++++++++++ .../internal/pcollections/HashTreePMap.java | 51 +++ .../jvm/internal/pcollections/IntTree.java | 309 ++++++++++++++++++ .../internal/pcollections/IntTreePMap.java | 163 +++++++++ .../internal/pcollections/PCollection.java | 47 +++ .../jvm/internal/pcollections/PMap.java | 45 +++ .../jvm/internal/pcollections/PSequence.java | 69 ++++ .../jvm/internal/pcollections/PStack.java | 53 +++ .../pcollections/SimpleImmutableEntry.java | 148 +++++++++ license/third_party/pcollections_LICENSE.txt | 19 ++ 12 files changed, 1291 insertions(+) create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PCollection.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PSequence.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java create mode 100644 license/third_party/pcollections_LICENSE.txt diff --git a/compiler/tests/org/jetbrains/jet/parsing/JetCodeConformanceTest.java b/compiler/tests/org/jetbrains/jet/parsing/JetCodeConformanceTest.java index 7c092def797..534f6719e38 100644 --- a/compiler/tests/org/jetbrains/jet/parsing/JetCodeConformanceTest.java +++ b/compiler/tests/org/jetbrains/jet/parsing/JetCodeConformanceTest.java @@ -36,6 +36,8 @@ public class JetCodeConformanceTest extends TestCase { private static final Pattern SOURCES_FILE_PATTERN = Pattern.compile("(.+\\.java|.+\\.kt|.+\\.js)"); private static final List EXCLUDED_FILES_AND_DIRS = Arrays.asList( new File("android.tests.dependencies"), + new File("core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections"), + new File("libraries/tools/runtime/target/copied-sources"), new File("dependencies"), new File("examples"), new File("js/js.translator/qunit/qunit.js"), diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java new file mode 100644 index 00000000000..b529b6580c8 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java @@ -0,0 +1,210 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.AbstractSequentialList; +import java.util.Collection; +import java.util.Iterator; +import java.util.ListIterator; + + + +/** + * + * A simple persistent stack of non-null values. + *

+ * This implementation is thread-safe (assuming Java's AbstractSequentialList is thread-safe), + * although its iterators may not be. + * + * @author harold + * + * @param + */ +public final class ConsPStack extends AbstractSequentialList implements PStack { +//// STATIC FACTORY METHODS //// + private static final ConsPStack EMPTY = new ConsPStack(); + + /** + * @param + * @return an empty stack + */ + @SuppressWarnings("unchecked") + public static ConsPStack empty() { + return (ConsPStack)EMPTY; } + + /** + * @param + * @param e + * @return empty().plus(e) + */ + public static ConsPStack singleton(final E e) { + return ConsPStack.empty().plus(e); } + + /** + * @param + * @param list + * @return a stack consisting of the elements of list in the order of list.iterator() + */ + @SuppressWarnings("unchecked") + public static ConsPStack from(final Collection list) { + if(list instanceof ConsPStack) + return (ConsPStack)list; //(actually we only know it's ConsPStack) + // but that's good enough for an immutable + // (i.e. we can't mess someone else up by adding the wrong type to it) + return from(list.iterator()); + } + + private static ConsPStack from(final Iterator i) { + if(!i.hasNext()) return empty(); + E e = i.next(); + return from(i).plus(e); + } + + +//// PRIVATE CONSTRUCTORS //// + private final E first; private final ConsPStack rest; + private final int size; + // not externally instantiable (or subclassable): + private ConsPStack() { // EMPTY constructor + if(EMPTY!=null) + throw new RuntimeException("empty constructor should only be used once"); + size = 0; first=null; rest=null; + } + private ConsPStack(final E first, final ConsPStack rest) { + this.first = first; this.rest = rest; + + size = 1 + rest.size; + } + + +//// REQUIRED METHODS FROM AbstractSequentialList //// + @Override + public int size() { + return size; } + + @Override + public ListIterator listIterator(final int index) { + if(index<0 || index>size) throw new IndexOutOfBoundsException(); + + return new ListIterator() { + int i = index; + ConsPStack next = subList(index); + + public boolean hasNext() { + return next.size>0; } + public boolean hasPrevious() { + return i>0; } + public int nextIndex() { + return index; } + public int previousIndex() { + return index-1; } + public E next() { + E e = next.first; + next = next.rest; + return e; + } + public E previous() { + System.err.println("ConsPStack.listIterator().previous() is inefficient, don't use it!"); + next = subList(index-1); // go from beginning... + return next.first; + } + + public void add(final E o) { + throw new UnsupportedOperationException(); } + public void remove() { + throw new UnsupportedOperationException(); } + public void set(final E o) { + throw new UnsupportedOperationException(); } + }; + } + + +//// OVERRIDDEN METHODS FROM AbstractSequentialList //// + @Override + public ConsPStack subList(final int start, final int end) { + if(start<0 || end>size || start>end) + throw new IndexOutOfBoundsException(); + if(end==size) // want a substack + return subList(start); // this is faster + if(start==end) // want nothing + return empty(); + if(start==0) // want the current element + return new ConsPStack(first, rest.subList(0, end-1)); + // otherwise, don't want the current element: + return rest.subList(start-1, end-1); + } + + +//// IMPLEMENTED METHODS OF PStack //// + public ConsPStack plus(final E e) { + return new ConsPStack(e, this); + } + + public ConsPStack plusAll(final Collection list) { + ConsPStack result = this; + for(E e : list) + result = result.plus(e); + return result; + } + + public ConsPStack plus(final int i, final E e) { + if(i<0 || i>size) + throw new IndexOutOfBoundsException(); + if(i==0) // insert at beginning + return plus(e); + return new ConsPStack(first, rest.plus(i-1, e)); + } + + public ConsPStack plusAll(final int i, final Collection list) { + // TODO inefficient if list.isEmpty() + if(i<0 || i>size) + throw new IndexOutOfBoundsException(); + if(i==0) + return plusAll(list); + return new ConsPStack(first, rest.plusAll(i-1, list)); + } + + public ConsPStack minus(final Object e) { + if(size==0) + return this; + if(first.equals(e)) // found it + return rest; // don't recurse (only remove one) + // otherwise keep looking: + ConsPStack newRest = rest.minus(e); + if(newRest==rest) return this; + return new ConsPStack(first, newRest); + } + + public ConsPStack minus(final int i) { + return minus(get(i)); + } + + public ConsPStack minusAll(final Collection list) { + if(size==0) + return this; + if(list.contains(first)) // get rid of current element + return rest.minusAll(list); // recursively delete all + // either way keep looking: + ConsPStack newRest = rest.minusAll(list); + if(newRest==rest) return this; + return new ConsPStack(first, newRest); + } + + public ConsPStack with(final int i, final E e) { + if(i<0 || i>=size) + throw new IndexOutOfBoundsException(); + if(i==0) { + if(first.equals(e)) return this; + return new ConsPStack(e, rest); + } + ConsPStack newRest = rest.with(i-1, e); + if(newRest==rest) return this; + return new ConsPStack(first, newRest); + } + + public ConsPStack subList(final int start) { + if(start<0 || start>size) + throw new IndexOutOfBoundsException(); + if(start==0) + return this; + return rest.subList(start-1); + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java new file mode 100644 index 00000000000..f2c777c364b --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java @@ -0,0 +1,175 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + + + + +/** + * + * A persistent map from non-null keys to non-null values. + *

+ * This map uses a given integer map to map hashcodes to lists of elements + * with the same hashcode. Thus if all elements have the same hashcode, performance + * is reduced to that of an association list. + *

+ * This implementation is thread-safe (assuming Java's AbstractMap and AbstractSet are thread-safe), + * although its iterators may not be. + * + * @author harold + * + * @param + * @param + */ +public final class HashPMap extends AbstractMap implements PMap { +//// STATIC FACTORY METHODS //// + /** + * @param + * @param + * @param intMap + * @return a map backed by an empty version of intMap, + * i.e. backed by intMap.minusAll(intMap.keySet()) + */ + public static HashPMap empty(final PMap>> intMap) { + return new HashPMap(intMap.minusAll(intMap.keySet()), 0); } + + +//// PRIVATE CONSTRUCTORS //// + private final PMap>> intMap; + private final int size; + // not externally instantiable (or subclassable): + private HashPMap(final PMap>> intMap, final int size) { + this.intMap = intMap; this.size = size; } + + +//// REQUIRED METHODS FROM AbstractMap //// + // this cache variable is thread-safe since assignment in Java is atomic: + private Set> entrySet = null; + @Override + public Set> entrySet() { + if(entrySet==null) + entrySet = new AbstractSet>() { + // REQUIRED METHODS OF AbstractSet // + @Override + public int size() { + return size; } + @Override + public Iterator> iterator() { + return new SequenceIterator>(intMap.values().iterator()); } + // OVERRIDDEN METHODS OF AbstractSet // + @Override + public boolean contains(final Object e) { + if(!(e instanceof Entry)) + return false; + V value = get(((Entry)e).getKey()); + return value!=null && value.equals(((Entry)e).getValue()); + } + }; + return entrySet; + } + + +//// OVERRIDDEN METHODS FROM AbstractMap //// + @Override + public int size() { + return size; } + + @Override + public boolean containsKey(final Object key) { + return keyIndexIn(getEntries(key.hashCode()), key) != -1; } + + @Override + public V get(final Object key) { + PSequence> entries = getEntries(key.hashCode()); + for(Entry entry : entries) + if(entry.getKey().equals(key)) + return entry.getValue(); + return null; + } + + +//// IMPLEMENTED METHODS OF PMap//// + public HashPMap plusAll(final Map map) { + HashPMap result = this; + for(Entry entry : map.entrySet()) + result = result.plus(entry.getKey(), entry.getValue()); + return result; + } + + public HashPMap minusAll(final Collection keys) { + HashPMap result = this; + for(Object key : keys) + result = result.minus(key); + return result; + } + + public HashPMap plus(final K key, final V value) { + PSequence> entries = getEntries(key.hashCode()); + int size0 = entries.size(), + i = keyIndexIn(entries, key); + if(i!=-1) entries = entries.minus(i); + entries = entries.plus(new SimpleImmutableEntry(key, value)); + return new HashPMap(intMap.plus(key.hashCode(), entries), + size-size0+entries.size()); + } + + public HashPMap minus(final Object key) { + PSequence> entries = getEntries(key.hashCode()); + int i = keyIndexIn(entries, key); + if(i==-1) // key not in this + return this; + entries = entries.minus(i); + if(entries.size()==0) // get rid of the entire hash entry + return new HashPMap(intMap.minus(key.hashCode()), + size-1); + // otherwise replace hash entry with new smaller one: + return new HashPMap(intMap.plus(key.hashCode(), entries), + size-1); + } + + +//// PRIVATE UTILITIES //// + private PSequence> getEntries(final int hash) { + PSequence> entries = intMap.get(hash); + if(entries==null) return ConsPStack.empty(); + return entries; + } + + +//// PRIVATE STATIC UTILITIES //// + private static int keyIndexIn(final PSequence> entries, final Object key) { + int i=0; + for(Entry entry : entries) { + if(entry.getKey().equals(key)) + return i; + i++; + } + return -1; + } + + static class SequenceIterator implements Iterator { + private final Iterator> i; + private PSequence seq = ConsPStack.empty(); + SequenceIterator(Iterator> i) { + this.i = i; } + + public boolean hasNext() { + return seq.size()>0 || i.hasNext(); } + + public E next() { + if(seq.size()==0) + seq = i.next(); + final E result = seq.get(0); + seq = seq.subList(1, seq.size()); + return result; + } + + public void remove() { + throw new UnsupportedOperationException(); } + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java new file mode 100644 index 00000000000..46b3ab9c195 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java @@ -0,0 +1,51 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.Map; +import java.util.Map.Entry; + + + + +/** + * + * A static convenience class for creating efficient persistent maps. + *

+ * This class simply creates HashPMaps backed by IntTreePMaps. + * + * @author harold + */ +public final class HashTreePMap { + // not instantiable (or subclassable): + private HashTreePMap() {} + + private static final HashPMap EMPTY + = HashPMap.empty(IntTreePMap.>>empty()); + + /** + * @param + * @param + * @return an empty map + */ + @SuppressWarnings("unchecked") + public static HashPMap empty() { + return (HashPMap)EMPTY; } + + /** + * @param + * @param + * @param key + * @param value + * @return empty().plus(key, value) + */ + public static HashPMap singleton(final K key, final V value) { + return HashTreePMap.empty().plus(key, value); } + + /** + * @param + * @param + * @param map + * @return empty().plusAll(map) + */ + public static HashPMap from(final Map map) { + return HashTreePMap.empty().plusAll(map); } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java new file mode 100644 index 00000000000..d5a1ea7b2bb --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java @@ -0,0 +1,309 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.Iterator; +import java.util.Map.Entry; + + + + +/** + * + * A non-public utility class for persistent balanced tree maps with integer keys. + *

+ * To allow for efficiently increasing all keys above a certain value or decreasing + * all keys below a certain value, the keys values are stored relative to their parent. + * This makes this map a good backing for fast insertion and removal of indices in a + * vector. + *

+ * This implementation is thread-safe except for its iterators. + *

+ * Other than that, this tree is based on the Glasgow Haskell Compiler's Data.Map implementation, + * which in turn is based on "size balanced binary trees" as described by: + *

+ * Stephen Adams, "Efficient sets: a balancing act", + * Journal of Functional Programming 3(4):553-562, October 1993, + * http://www.swiss.ai.mit.edu/~adams/BB/. + *

+ * J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance", + * SIAM journal of computing 2(1), March 1973. + * + * @author harold + * + * @param + */ +class IntTree { + // marker value: + static final IntTree EMPTYNODE = new IntTree(); + + private final long key; // we use longs so relative keys can express all ints + // (e.g. if this has key -10 and right has 'absolute' key MAXINT, + // then its relative key is MAXINT+10 which overflows) + // there might be some way to deal with this based on left-verse-right logic, + // but that sounds like a mess. + private final V value; // null value means this is empty node + private final IntTree left, right; + private final int size; + private IntTree() { + if(EMPTYNODE!=null) + throw new RuntimeException("empty constructor should only be used once"); + size = 0; + + key=0; value=null; left=null; right=null; + } + private IntTree(final long key, final V value, final IntTree left, final IntTree right) { + this.key = key; this.value = value; + this.left = left; this.right = right; + size = 1 + left.size + right.size; + } + + private IntTree withKey(final long newKey) { + if(size==0 || newKey==key) return this; + return new IntTree(newKey, value, left, right); } + + Iterator> iterator() { + return new EntryIterator(this); } + + int size() { + return size; } + + boolean containsKey(final long key) { + if(size==0) + return false; + if(key < this.key) + return left.containsKey(key-this.key); + if(key > this.key) + return right.containsKey(key-this.key); + // otherwise key==this.key: + return true; + } + + V get(final long key) { + if(size==0) + return null; + if(key < this.key) + return left.get(key-this.key); + if(key > this.key) + return right.get(key-this.key); + // otherwise key==this.key: + return value; + } + + IntTree plus(final long key, final V value) { + if(size==0) + return new IntTree(key, value, this, this); + if(key < this.key) + return rebalanced(left.plus(key-this.key, value), right); + if(key > this.key) + return rebalanced(left, right.plus(key-this.key, value)); + // otherwise key==this.key, so we simply replace this, with no effect on balance: + if(value==this.value) + return this; + return new IntTree(key, value, left, right); + } + + IntTree minus(final long key) { + if(size==0) + return this; + if(key < this.key) + return rebalanced(left.minus(key-this.key), right); + if(key > this.key) + return rebalanced(left, right.minus(key-this.key)); + + // otherwise key==this.key, so we are killing this node: + + if(left.size==0) // we can just become right node + // make key 'absolute': + return right.withKey(right.key+this.key); + if(right.size==0) // we can just become left node + return left.withKey(left.key+this.key); + + // otherwise replace this with the next key (i.e. the smallest key to the right): + + // TODO have minNode() instead of minKey to avoid having to call get() + // TODO get node from larger subtree, i.e. if left.size>right.size use left.maxNode() + // TODO have faster minusMin() instead of just using minus() + + long newKey = right.minKey() + this.key; + //(right.minKey() is relative to this; adding this.key makes it 'absolute' + // where 'absolute' really means relative to the parent of this) + + V newValue = right.get(newKey-this.key); + // now that we've got the new stuff, take it out of the right subtree: + IntTree newRight = right.minus(newKey-this.key); + + // lastly, make the subtree keys relative to newKey (currently they are relative to this.key): + newRight = newRight.withKey( (newRight.key+this.key) - newKey ); + // left is definitely not empty: + IntTree newLeft = left.withKey( (left.key+this.key) - newKey ); + + return rebalanced(newKey, newValue, newLeft, newRight); + } + + /** + * Changes every key k>=key to k+delta. + * + * This method will create an _invalid_ tree if delta<0 + * and the distance between the smallest k>=key in this + * and the largest j changeKeysAbove(final long key, final int delta) { + if(size==0 || delta==0) + return this; + + if(this.key>=key) + // adding delta to this.key changes the keys of _all_ children of this, + // so we now need to un-change the children of this smaller than key, + // all of which are to the left. note that we still use the 'old' relative key...: + return new IntTree(this.key+delta, value, left.changeKeysBelow(key-this.key, -delta), right); + + // otherwise, doesn't apply yet, look to the right: + IntTree newRight = right.changeKeysAbove(key-this.key, delta); + if(newRight==right) return this; + return new IntTree(this.key, value, left, newRight); + } + + /** + * Changes every key k0 + * and the distance between the largest k=key in this is delta or less. + * + * In other words, this method must not result in any overlap or change + * in the order of the keys in this, since the tree _structure_ is + * not being changed at all. + */ + IntTree changeKeysBelow(final long key, final int delta) { + if(size==0 || delta==0) + return this; + + if(this.key(this.key+delta, value, left, right.changeKeysAbove(key-this.key, -delta)); + + // otherwise, doesn't apply yet, look to the left: + IntTree newLeft = left.changeKeysBelow(key-this.key, delta); + if(newLeft==left) return this; + return new IntTree(this.key, value, newLeft, right); + } + + // min key in this: + private long minKey() { + if(left.size==0) + return key; + // make key 'absolute' (i.e. relative to the parent of this): + return left.minKey() + this.key; + } + + private IntTree rebalanced(final IntTree newLeft, final IntTree newRight) { + if(newLeft==left && newRight==right) + return this; // already balanced + return rebalanced(key, value, newLeft, newRight); + } + + private static final int OMEGA = 5; + private static final int ALPHA = 2; + // rebalance a tree that is off-balance by at most 1: + private static IntTree rebalanced(final long key, final V value, + final IntTree left, final IntTree right) { + if(left.size + right.size > 1) { + if(left.size >= OMEGA*right.size) { // rotate to the right + IntTree ll = left.left, lr = left.right; + if(lr.size < ALPHA*ll.size) // single rotation + return new IntTree(left.key+key, left.value, + ll, + new IntTree(-left.key, value, + lr.withKey(lr.key+left.key), + right)); + else { // double rotation: + IntTree lrl = lr.left, lrr = lr.right; + return new IntTree(lr.key+left.key+key, lr.value, + new IntTree(-lr.key, left.value, + ll, + lrl.withKey(lrl.key+lr.key)), + new IntTree(-left.key-lr.key, value, + lrr.withKey(lrr.key+lr.key+left.key), + right)); + } + } + else if(right.size >= OMEGA*left.size) { // rotate to the left + IntTree rl = right.left, rr = right.right; + if(rl.size < ALPHA*rr.size) // single rotation + return new IntTree(right.key+key, right.value, + new IntTree(-right.key, value, + left, + rl.withKey(rl.key+right.key)), + rr); + else { // double rotation: + IntTree rll = rl.left, rlr = rl.right; + return new IntTree(rl.key+right.key+key, rl.value, + new IntTree(-right.key-rl.key, value, + left, + rll.withKey(rll.key+rl.key+right.key)), + new IntTree(-rl.key, right.value, + rlr.withKey(rlr.key+rl.key), + rr)); + } + } + } + // otherwise already balanced enough: + return new IntTree(key, value, left, right); + } + + +////entrySet().iterator() IMPLEMENTATION //// + // TODO make this a ListIterator? + private static final class EntryIterator implements Iterator> { + private PStack> stack = ConsPStack.empty(); //path of nonempty nodes + private int key = 0; // note we use _int_ here since this is a truly absolute key + + EntryIterator(final IntTree root) { + gotoMinOf(root); } + + public boolean hasNext() { + return stack.size()>0; } + + public Entry next() { + IntTree node = stack.get(0); + final Entry result = new SimpleImmutableEntry(key, node.value); + + // find next node. + // we've already done everything smaller, + // so try least larger node: + + if(node.right.size>0) // we can descend to the right + gotoMinOf(node.right); + + else // can't descend to the right -- try ascending to the right + while (true) { // find current node's least larger ancestor, if any + key -= node.key; // revert to parent's key + stack = stack.subList(1); // climb up to parent + // if parent was larger than child or there was no parent, we're done: + if(node.key<0 || stack.size()==0) + break; + // otherwise parent was smaller -- try its parent: + node = stack.get(0); + } + + return result; + } + + public void remove() { + throw new UnsupportedOperationException(); } + + // extend the stack to its least non-empty node: + private void gotoMinOf(IntTree node) { + while(node.size>0) { + stack = stack.plus(node); + key += node.key; + node = node.left; + } + } + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java new file mode 100644 index 00000000000..4c144faf378 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java @@ -0,0 +1,163 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + + + + +/** + * + * An efficient persistent map from integer keys to non-null values. + *

+ * Iteration occurs in the integer order of the keys. + *

+ * This implementation is thread-safe (assuming Java's AbstractMap and AbstractSet are thread-safe), + * although its iterators may not be. + *

+ * The balanced tree is based on the Glasgow Haskell Compiler's Data.Map implementation, + * which in turn is based on "size balanced binary trees" as described by: + *

+ * Stephen Adams, "Efficient sets: a balancing act", + * Journal of Functional Programming 3(4):553-562, October 1993, + * http://www.swiss.ai.mit.edu/~adams/BB/. + *

+ * J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance", + * SIAM journal of computing 2(1), March 1973. + * + * @author harold + * + * @param + */ +public final class IntTreePMap extends AbstractMap implements PMap { +//// STATIC FACTORY METHODS //// + private static final IntTreePMap EMPTY = new IntTreePMap(IntTree.EMPTYNODE); + + /** + * @param + * @return an empty map + */ + @SuppressWarnings("unchecked") + public static IntTreePMap empty() { + return (IntTreePMap)EMPTY; } + + /** + * @param + * @param key + * @param value + * @return empty().plus(key, value) + */ + public static IntTreePMap singleton(final Integer key, final V value) { + return IntTreePMap.empty().plus(key, value); } + + /** + * @param + * @param map + * @return empty().plusAll(map) + */ + @SuppressWarnings("unchecked") + public static IntTreePMap from(final Map map) { + if(map instanceof IntTreePMap) + return (IntTreePMap)map; //(actually we only know it's IntTreePMap) + // but that's good enough for an immutable + // (i.e. we can't mess someone else up by adding the wrong type to it) + return IntTreePMap.empty().plusAll(map); } + + +//// PRIVATE CONSTRUCTORS //// + private final IntTree root; + // not externally instantiable (or subclassable): + private IntTreePMap(final IntTree root) { + this.root = root; } + private IntTreePMap withRoot(final IntTree root) { + if(root==this.root) return this; + return new IntTreePMap(root); } + + +//// UNINHERITED METHODS OF IntTreePMap //// + IntTreePMap withKeysChangedAbove(final int key, final int delta) { + // TODO check preconditions of changeKeysAbove() + // TODO make public? + return withRoot( root.changeKeysAbove(key, delta) ); + } + + IntTreePMap withKeysChangedBelow(final int key, final int delta) { + // TODO check preconditions of changeKeysAbove() + // TODO make public? + return withRoot( root.changeKeysBelow(key, delta) ); + } + +//// REQUIRED METHODS FROM AbstractMap //// + // this cache variable is thread-safe, since assignment in Java is atomic: + private Set> entrySet = null; + @Override + public Set> entrySet() { + if(entrySet==null) + entrySet = new AbstractSet>() { + // REQUIRED METHODS OF AbstractSet // + @Override + public int size() { // same as Map + return IntTreePMap.this.size(); } + @Override + public Iterator> iterator() { + return root.iterator(); } + // OVERRIDDEN METHODS OF AbstractSet // + @Override + public boolean contains(final Object e) { + if(!(e instanceof Entry)) + return false; + V value = get(((Entry)e).getKey()); + return value!=null && value.equals(((Entry)e).getValue()); + } + }; + return entrySet; + } + + +//// OVERRIDDEN METHODS FROM AbstractMap //// + @Override + public int size() { + return root.size(); } + + @Override + public boolean containsKey(final Object key) { + if(!(key instanceof Integer)) + return false; + return root.containsKey((Integer)key); + } + + @Override + public V get(final Object key) { + if(!(key instanceof Integer)) + return null; + return root.get((Integer)key); + } + + +//// IMPLEMENTED METHODS OF PMap//// + public IntTreePMap plus(final Integer key, final V value) { + return withRoot( root.plus(key, value) ); } + + public IntTreePMap minus(final Object key) { + if(!(key instanceof Integer)) return this; + return withRoot( root.minus((Integer)key) ); } + + public IntTreePMap plusAll(final Map map) { + IntTree root = this.root; + for(Entry entry : map.entrySet()) + root = root.plus(entry.getKey(), entry.getValue()); + return withRoot(root); + } + + public IntTreePMap minusAll(final Collection keys) { + IntTree root = this.root; + for(Object key : keys) + if(key instanceof Integer) + root = root.minus((Integer)key); + return withRoot(root); + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PCollection.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PCollection.java new file mode 100644 index 00000000000..333acc4ca15 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PCollection.java @@ -0,0 +1,47 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.Collection; + +/** + * + * An immutable, persistent collection of non-null elements of type E. + * + * @author harold + * + * @param + */ +public interface PCollection extends Collection { + + /** + * @param e non-null + * @return a collection which contains e and all of the elements of this + */ + public PCollection plus(E e); + + /** + * @param list contains no null elements + * @return a collection which contains all of the elements of list and this + */ + public PCollection plusAll(Collection list); + + /** + * @param e + * @return this with a single instance of e removed, if e is in this + */ + public PCollection minus(Object e); + + /** + * @param list + * @return this with all elements of list completely removed + */ + public PCollection minusAll(Collection list); + + // TODO public PCollection retainingAll(Collection list); + + @Deprecated boolean add(E o); + @Deprecated boolean remove(Object o); + @Deprecated boolean addAll(Collection c); + @Deprecated boolean removeAll(Collection c); + @Deprecated boolean retainAll(Collection c); + @Deprecated void clear(); +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java new file mode 100644 index 00000000000..bdfd4f54896 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java @@ -0,0 +1,45 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.Collection; +import java.util.Map; + +/** + * + * An immutable, persistent map from non-null keys of type K to non-null values of type V. + * + * @author harold + * + * @param + * @param + */ +public interface PMap extends Map { + /** + * @param key non-null + * @param value non-null + * @return a map with the mappings of this but with key mapped to value + */ + public PMap plus(K key, V value); + + /** + * @param map + * @return this combined with map, with map's mappings used for any keys in both map and this + */ + public PMap plusAll(Map map); + + /** + * @param key + * @return a map with the mappings of this but with no value for key + */ + public PMap minus(Object key); + + /** + * @param keys + * @return a map with the mappings of this but with no value for any element of keys + */ + public PMap minusAll(Collection keys); + + @Deprecated V put(K k, V v); + @Deprecated V remove(Object k); + @Deprecated void putAll(Map m); + @Deprecated void clear(); +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PSequence.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PSequence.java new file mode 100644 index 00000000000..3be82dcec0f --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PSequence.java @@ -0,0 +1,69 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.Collection; +import java.util.List; + +/** + * + * An immutable, persistent indexed collection. + * + * @author harold + * + * @param + */ +public interface PSequence extends PCollection, List { + + //@Override + public PSequence plus(E e); + + //@Override + public PSequence plusAll(Collection list); + + /** + * @param i + * @param e + * @return a sequence consisting of the elements of this with e replacing the element at index i. + * @throws IndexOutOfBOundsException if i<0 || i>=this.size() + */ + public PSequence with(int i, E e); + + /** + * @param i + * @param e non-null + * @return a sequence consisting of the elements of this with e inserted at index i. + * @throws IndexOutOfBOundsException if i<0 || i>this.size() + */ + public PSequence plus(int i, E e); + + /** + * @param i + * @param list + * @return a sequence consisting of the elements of this with list inserted at index i. + * @throws IndexOutOfBOundsException if i<0 || i>this.size() + */ + public PSequence plusAll(int i, Collection list); + + /** + * Returns a sequence consisting of the elements of this without the first occurrence of e. + */ + //@Override + public PSequence minus(Object e); + + //@Override + public PSequence minusAll(Collection list); + + /** + * @param i + * @return a sequence consisting of the elements of this with the element at index i removed. + * @throws IndexOutOfBOundsException if i<0 || i>=this.size() + */ + public PSequence minus(int i); + + //@Override + public PSequence subList(int start, int end); + + @Deprecated boolean addAll(int index, Collection c); + @Deprecated E set(int index, E element); + @Deprecated void add(int index, E element); + @Deprecated E remove(int index); +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java new file mode 100644 index 00000000000..ca68a69360e --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java @@ -0,0 +1,53 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.Collection; + +/** + * + * An immutable, persistent stack. + * + * @author harold + * + * @param + */ +public interface PStack extends PSequence { + + /** + * Returns a stack consisting of the elements of this with e prepended. + */ + //@Override + public PStack plus(E e); + + /** + * Returns a stack consisting of the elements of this with list prepended in reverse. + */ + //@Override + public PStack plusAll(Collection list); + + //@Override + public PStack with(int i, E e); + + //@Override + public PStack plus(int i, E e); + + //@Override + public PStack plusAll(int i, Collection list); + + //@Override + public PStack minus(Object e); + + //@Override + public PStack minusAll(Collection list); + + //@Override + public PStack minus(int i); + + //@Override + public PStack subList(int start, int end); + + /** + * @param start + * @return subList(start,this.size()) + */ + public PStack subList(int start); +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java new file mode 100644 index 00000000000..71452649e25 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java @@ -0,0 +1,148 @@ +package kotlin.reflect.jvm.internal.pcollections; + +import java.util.Map; +import java.util.Map.Entry; + + +/** + * (Taken from Java 6 code, so pcollections can be Java 5-compatible.) + *

+ * An Entry maintaining an immutable key and value. This class + * does not support method setValue. This class may be + * convenient in methods that return thread-safe snapshots of + * key-value mappings. + * + * @since 1.6 + */ +/*public*/ final class SimpleImmutableEntry + implements Map.Entry, java.io.Serializable +{ + private static final long serialVersionUID = 7138329143949025153L; + + private final K key; + private final V value; + + /** + * Creates an entry representing a mapping from the specified + * key to the specified value. + * + * @param key the key represented by this entry + * @param value the value represented by this entry + */ + public SimpleImmutableEntry(K key, V value) { + this.key = key; + this.value = value; + } + + /** + * Creates an entry representing the same mapping as the + * specified entry. + * + * @param entry the entry to copy + */ + public SimpleImmutableEntry(Entry entry) { + this.key = entry.getKey(); + this.value = entry.getValue(); + } + + /** + * Returns the key corresponding to this entry. + * + * @return the key corresponding to this entry + */ + public K getKey() { + return key; + } + + /** + * Returns the value corresponding to this entry. + * + * @return the value corresponding to this entry + */ + public V getValue() { + return value; + } + + /** + * Replaces the value corresponding to this entry with the specified + * value (optional operation). This implementation simply throws + * UnsupportedOperationException, as this class implements + * an immutable map entry. + * + * @param value new value to be stored in this entry + * @return (Does not return) + * @throws UnsupportedOperationException always + */ + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + + /** + * Compares the specified object with this entry for equality. + * Returns {@code true} if the given object is also a map entry and + * the two entries represent the same mapping. More formally, two + * entries {@code e1} and {@code e2} represent the same mapping + * if

+	 *   (e1.getKey()==null ?
+	 *    e2.getKey()==null :
+	 *    e1.getKey().equals(e2.getKey()))
+	 *   &&
+	 *   (e1.getValue()==null ?
+	 *    e2.getValue()==null :
+	 *    e1.getValue().equals(e2.getValue()))
+ * This ensures that the {@code equals} method works properly across + * different implementations of the {@code Map.Entry} interface. + * + * @param o object to be compared for equality with this map entry + * @return {@code true} if the specified object is equal to this map + * entry + * @see #hashCode + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return eq(key, e.getKey()) && eq(value, e.getValue()); + } + + /** + * Returns the hash code value for this map entry. The hash code + * of a map entry {@code e} is defined to be:
+	 *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+	 *   (e.getValue()==null ? 0 : e.getValue().hashCode())
+ * This ensures that {@code e1.equals(e2)} implies that + * {@code e1.hashCode()==e2.hashCode()} for any two Entries + * {@code e1} and {@code e2}, as required by the general + * contract of {@link Object#hashCode}. + * + * @return the hash code value for this map entry + * @see #equals + */ + @Override + public int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + /** + * Returns a String representation of this map entry. This + * implementation returns the string representation of this + * entry's key followed by the equals character ("=") + * followed by the string representation of this entry's value. + * + * @return a String representation of this map entry + */ + @Override + public String toString() { + return key + "=" + value; + } + + /** + * Utility method for SimpleEntry and SimpleImmutableEntry. + * Test for equality, checking for nulls. + */ + private static boolean eq(Object o1, Object o2) { + return o1 == null ? o2 == null : o1.equals(o2); + } +} diff --git a/license/third_party/pcollections_LICENSE.txt b/license/third_party/pcollections_LICENSE.txt new file mode 100644 index 00000000000..345a0dad954 --- /dev/null +++ b/license/third_party/pcollections_LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2008 Harold Cooper + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From d83df541b75eed449f129156dad7bc5a728eb6de Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 9 Jun 2014 22:38:58 +0400 Subject: [PATCH 15/38] Remove unneeded code and beautify HashPMap and its dependencies --- .../jvm/internal/pcollections/ConsPStack.java | 311 +++++------ .../jvm/internal/pcollections/HashPMap.java | 220 +++----- .../internal/pcollections/HashTreePMap.java | 51 -- .../jvm/internal/pcollections/IntTree.java | 485 ++++++++---------- .../internal/pcollections/IntTreePMap.java | 171 ++---- .../internal/pcollections/PCollection.java | 47 -- .../jvm/internal/pcollections/PMap.java | 45 +- .../jvm/internal/pcollections/PSequence.java | 69 --- .../jvm/internal/pcollections/PStack.java | 49 +- .../pcollections/SimpleImmutableEntry.java | 225 ++++---- 10 files changed, 547 insertions(+), 1126 deletions(-) delete mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java delete mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PCollection.java delete mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PSequence.java diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java index b529b6580c8..90ea3b6dee2 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java @@ -1,210 +1,141 @@ package kotlin.reflect.jvm.internal.pcollections; -import java.util.AbstractSequentialList; -import java.util.Collection; import java.util.Iterator; import java.util.ListIterator; - - +import java.util.NoSuchElementException; /** - * * A simple persistent stack of non-null values. - *

- * This implementation is thread-safe (assuming Java's AbstractSequentialList is thread-safe), - * although its iterators may not be. - * - * @author harold + *

+ * This implementation is thread-safe, although its iterators may not be. * - * @param + * @author harold */ -public final class ConsPStack extends AbstractSequentialList implements PStack { -//// STATIC FACTORY METHODS //// - private static final ConsPStack EMPTY = new ConsPStack(); - - /** - * @param - * @return an empty stack - */ - @SuppressWarnings("unchecked") - public static ConsPStack empty() { - return (ConsPStack)EMPTY; } - - /** - * @param - * @param e - * @return empty().plus(e) - */ - public static ConsPStack singleton(final E e) { - return ConsPStack.empty().plus(e); } - - /** - * @param - * @param list - * @return a stack consisting of the elements of list in the order of list.iterator() - */ - @SuppressWarnings("unchecked") - public static ConsPStack from(final Collection list) { - if(list instanceof ConsPStack) - return (ConsPStack)list; //(actually we only know it's ConsPStack) - // but that's good enough for an immutable - // (i.e. we can't mess someone else up by adding the wrong type to it) - return from(list.iterator()); - } - - private static ConsPStack from(final Iterator i) { - if(!i.hasNext()) return empty(); - E e = i.next(); - return from(i).plus(e); - } +public final class ConsPStack implements PStack { + private static final ConsPStack EMPTY = new ConsPStack(); - -//// PRIVATE CONSTRUCTORS //// - private final E first; private final ConsPStack rest; - private final int size; - // not externally instantiable (or subclassable): - private ConsPStack() { // EMPTY constructor - if(EMPTY!=null) - throw new RuntimeException("empty constructor should only be used once"); - size = 0; first=null; rest=null; - } - private ConsPStack(final E first, final ConsPStack rest) { - this.first = first; this.rest = rest; - - size = 1 + rest.size; - } - - -//// REQUIRED METHODS FROM AbstractSequentialList //// - @Override - public int size() { - return size; } - - @Override - public ListIterator listIterator(final int index) { - if(index<0 || index>size) throw new IndexOutOfBoundsException(); - - return new ListIterator() { - int i = index; - ConsPStack next = subList(index); + @SuppressWarnings("unchecked") + public static ConsPStack empty() { + return (ConsPStack) EMPTY; + } - public boolean hasNext() { - return next.size>0; } - public boolean hasPrevious() { - return i>0; } - public int nextIndex() { - return index; } - public int previousIndex() { - return index-1; } - public E next() { - E e = next.first; - next = next.rest; - return e; - } - public E previous() { - System.err.println("ConsPStack.listIterator().previous() is inefficient, don't use it!"); - next = subList(index-1); // go from beginning... - return next.first; - } + private final E first; + private final ConsPStack rest; + private final int size; - public void add(final E o) { - throw new UnsupportedOperationException(); } - public void remove() { - throw new UnsupportedOperationException(); } - public void set(final E o) { - throw new UnsupportedOperationException(); } - }; - } + private ConsPStack() { // EMPTY constructor + size = 0; + first = null; + rest = null; + } + private ConsPStack(E first, ConsPStack rest) { + this.first = first; + this.rest = rest; + this.size = 1 + rest.size; + } -//// OVERRIDDEN METHODS FROM AbstractSequentialList //// - @Override - public ConsPStack subList(final int start, final int end) { - if(start<0 || end>size || start>end) - throw new IndexOutOfBoundsException(); - if(end==size) // want a substack - return subList(start); // this is faster - if(start==end) // want nothing - return empty(); - if(start==0) // want the current element - return new ConsPStack(first, rest.subList(0, end-1)); - // otherwise, don't want the current element: - return rest.subList(start-1, end-1); - } - - -//// IMPLEMENTED METHODS OF PStack //// - public ConsPStack plus(final E e) { - return new ConsPStack(e, this); - } - - public ConsPStack plusAll(final Collection list) { - ConsPStack result = this; - for(E e : list) - result = result.plus(e); - return result; - } + public E get(int index) { + try { + return listIterator(index).next(); + } catch (NoSuchElementException e) { + throw new IndexOutOfBoundsException("Index: " + index); + } + } - public ConsPStack plus(final int i, final E e) { - if(i<0 || i>size) - throw new IndexOutOfBoundsException(); - if(i==0) // insert at beginning - return plus(e); - return new ConsPStack(first, rest.plus(i-1, e)); - } + @Override + public Iterator iterator() { + return listIterator(0); + } - public ConsPStack plusAll(final int i, final Collection list) { - // TODO inefficient if list.isEmpty() - if(i<0 || i>size) - throw new IndexOutOfBoundsException(); - if(i==0) - return plusAll(list); - return new ConsPStack(first, rest.plusAll(i-1, list)); - } - - public ConsPStack minus(final Object e) { - if(size==0) - return this; - if(first.equals(e)) // found it - return rest; // don't recurse (only remove one) - // otherwise keep looking: - ConsPStack newRest = rest.minus(e); - if(newRest==rest) return this; - return new ConsPStack(first, newRest); - } + @Override + public int size() { + return size; + } - public ConsPStack minus(final int i) { - return minus(get(i)); - } + public ListIterator listIterator(final int index) { + if (index < 0 || index > size) throw new IndexOutOfBoundsException(); - public ConsPStack minusAll(final Collection list) { - if(size==0) - return this; - if(list.contains(first)) // get rid of current element - return rest.minusAll(list); // recursively delete all - // either way keep looking: - ConsPStack newRest = rest.minusAll(list); - if(newRest==rest) return this; - return new ConsPStack(first, newRest); - } - - public ConsPStack with(final int i, final E e) { - if(i<0 || i>=size) - throw new IndexOutOfBoundsException(); - if(i==0) { - if(first.equals(e)) return this; - return new ConsPStack(e, rest); - } - ConsPStack newRest = rest.with(i-1, e); - if(newRest==rest) return this; - return new ConsPStack(first, newRest); - } + return new ListIterator() { + int i = index; + ConsPStack next = subList(index); - public ConsPStack subList(final int start) { - if(start<0 || start>size) - throw new IndexOutOfBoundsException(); - if(start==0) - return this; - return rest.subList(start-1); - } + @Override + public boolean hasNext() { + return next.size > 0; + } + + @Override + public boolean hasPrevious() { + return i > 0; + } + + @Override + public int nextIndex() { + return index; + } + + @Override + public int previousIndex() { + return index - 1; + } + + @Override + public E next() { + E e = next.first; + next = next.rest; + return e; + } + + @Override + public E previous() { + System.err.println("ConsPStack.listIterator().previous() is inefficient, don't use it!"); + next = subList(index - 1); // go from beginning... + return next.first; + } + + @Override + public void add(E o) { + throw new UnsupportedOperationException(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public void set(E o) { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public ConsPStack plus(E e) { + return new ConsPStack(e, this); + } + + public ConsPStack minus(Object e) { + if (size == 0) return this; + if (first.equals(e)) // found it + return rest; // don't recurse (only remove one) + // otherwise keep looking: + ConsPStack newRest = rest.minus(e); + if (newRest == rest) return this; + return new ConsPStack(first, newRest); + } + + @Override + public ConsPStack minus(int i) { + return minus(get(i)); + } + + public ConsPStack subList(int start) { + if (start < 0 || start > size) + throw new IndexOutOfBoundsException(); + if (start == 0) + return this; + return rest.subList(start - 1); + } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java index f2c777c364b..36c6abc287e 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java @@ -1,175 +1,87 @@ package kotlin.reflect.jvm.internal.pcollections; -import java.util.AbstractMap; -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - - - +import static java.util.Map.Entry; /** - * * A persistent map from non-null keys to non-null values. - *

+ *

* This map uses a given integer map to map hashcodes to lists of elements * with the same hashcode. Thus if all elements have the same hashcode, performance * is reduced to that of an association list. - *

- * This implementation is thread-safe (assuming Java's AbstractMap and AbstractSet are thread-safe), - * although its iterators may not be. - * - * @author harold + *

+ * This implementation is thread-safe, although its iterators may not be. * - * @param - * @param + * @author harold */ -public final class HashPMap extends AbstractMap implements PMap { -//// STATIC FACTORY METHODS //// - /** - * @param - * @param - * @param intMap - * @return a map backed by an empty version of intMap, - * i.e. backed by intMap.minusAll(intMap.keySet()) - */ - public static HashPMap empty(final PMap>> intMap) { - return new HashPMap(intMap.minusAll(intMap.keySet()), 0); } - +public final class HashPMap implements PMap { + public static final HashPMap EMPTY = new HashPMap(IntTreePMap.>>empty(), 0); -//// PRIVATE CONSTRUCTORS //// - private final PMap>> intMap; - private final int size; - // not externally instantiable (or subclassable): - private HashPMap(final PMap>> intMap, final int size) { - this.intMap = intMap; this.size = size; } + @SuppressWarnings("unchecked") + public static HashPMap empty() { + return (HashPMap) HashPMap.EMPTY; + } - -//// REQUIRED METHODS FROM AbstractMap //// - // this cache variable is thread-safe since assignment in Java is atomic: - private Set> entrySet = null; - @Override - public Set> entrySet() { - if(entrySet==null) - entrySet = new AbstractSet>() { - // REQUIRED METHODS OF AbstractSet // - @Override - public int size() { - return size; } - @Override - public Iterator> iterator() { - return new SequenceIterator>(intMap.values().iterator()); } - // OVERRIDDEN METHODS OF AbstractSet // - @Override - public boolean contains(final Object e) { - if(!(e instanceof Entry)) - return false; - V value = get(((Entry)e).getKey()); - return value!=null && value.equals(((Entry)e).getValue()); - } - }; - return entrySet; - } + private final IntTreePMap>> intMap; + private final int size; - -//// OVERRIDDEN METHODS FROM AbstractMap //// - @Override - public int size() { - return size; } + private HashPMap(IntTreePMap>> intMap, int size) { + this.intMap = intMap; + this.size = size; + } - @Override - public boolean containsKey(final Object key) { - return keyIndexIn(getEntries(key.hashCode()), key) != -1; } - - @Override - public V get(final Object key) { - PSequence> entries = getEntries(key.hashCode()); - for(Entry entry : entries) - if(entry.getKey().equals(key)) - return entry.getValue(); - return null; - } + public int size() { + return size; + } - -//// IMPLEMENTED METHODS OF PMap//// - public HashPMap plusAll(final Map map) { - HashPMap result = this; - for(Entry entry : map.entrySet()) - result = result.plus(entry.getKey(), entry.getValue()); - return result; - } + public boolean containsKey(Object key) { + return keyIndexIn(getEntries(key.hashCode()), key) != -1; + } - public HashPMap minusAll(final Collection keys) { - HashPMap result = this; - for(Object key : keys) - result = result.minus(key); - return result; - } - - public HashPMap plus(final K key, final V value) { - PSequence> entries = getEntries(key.hashCode()); - int size0 = entries.size(), - i = keyIndexIn(entries, key); - if(i!=-1) entries = entries.minus(i); - entries = entries.plus(new SimpleImmutableEntry(key, value)); - return new HashPMap(intMap.plus(key.hashCode(), entries), - size-size0+entries.size()); - } + @Override + public V get(Object key) { + PStack> entries = getEntries(key.hashCode()); + for (Entry entry : entries) + if (entry.getKey().equals(key)) + return entry.getValue(); + return null; + } - public HashPMap minus(final Object key) { - PSequence> entries = getEntries(key.hashCode()); - int i = keyIndexIn(entries, key); - if(i==-1) // key not in this - return this; - entries = entries.minus(i); - if(entries.size()==0) // get rid of the entire hash entry - return new HashPMap(intMap.minus(key.hashCode()), - size-1); - // otherwise replace hash entry with new smaller one: - return new HashPMap(intMap.plus(key.hashCode(), entries), - size-1); - } - - -//// PRIVATE UTILITIES //// - private PSequence> getEntries(final int hash) { - PSequence> entries = intMap.get(hash); - if(entries==null) return ConsPStack.empty(); - return entries; - } + @Override + public HashPMap plus(K key, V value) { + PStack> entries = getEntries(key.hashCode()); + int size0 = entries.size(); + int i = keyIndexIn(entries, key); + if (i != -1) entries = entries.minus(i); + entries = entries.plus(new SimpleImmutableEntry(key, value)); + return new HashPMap(intMap.plus(key.hashCode(), entries), size - size0 + entries.size()); + } - -//// PRIVATE STATIC UTILITIES //// - private static int keyIndexIn(final PSequence> entries, final Object key) { - int i=0; - for(Entry entry : entries) { - if(entry.getKey().equals(key)) - return i; - i++; - } - return -1; - } - - static class SequenceIterator implements Iterator { - private final Iterator> i; - private PSequence seq = ConsPStack.empty(); - SequenceIterator(Iterator> i) { - this.i = i; } + @Override + public HashPMap minus(Object key) { + PStack> entries = getEntries(key.hashCode()); + int i = keyIndexIn(entries, key); + if (i == -1) // key not in this + return this; + entries = entries.minus(i); + if (entries.size() == 0) // get rid of the entire hash entry + return new HashPMap(intMap.minus(key.hashCode()), size - 1); + // otherwise replace hash entry with new smaller one: + return new HashPMap(intMap.plus(key.hashCode(), entries), size - 1); + } - public boolean hasNext() { - return seq.size()>0 || i.hasNext(); } + private PStack> getEntries(int hash) { + PStack> entries = intMap.get(hash); + if (entries == null) return ConsPStack.empty(); + return entries; + } - public E next() { - if(seq.size()==0) - seq = i.next(); - final E result = seq.get(0); - seq = seq.subList(1, seq.size()); - return result; - } - - public void remove() { - throw new UnsupportedOperationException(); } - } + private static int keyIndexIn(PStack> entries, Object key) { + int i = 0; + for (Entry entry : entries) { + if (entry.getKey().equals(key)) + return i; + i++; + } + return -1; + } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java deleted file mode 100644 index 46b3ab9c195..00000000000 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java +++ /dev/null @@ -1,51 +0,0 @@ -package kotlin.reflect.jvm.internal.pcollections; - -import java.util.Map; -import java.util.Map.Entry; - - - - -/** - * - * A static convenience class for creating efficient persistent maps. - *

- * This class simply creates HashPMaps backed by IntTreePMaps. - * - * @author harold - */ -public final class HashTreePMap { - // not instantiable (or subclassable): - private HashTreePMap() {} - - private static final HashPMap EMPTY - = HashPMap.empty(IntTreePMap.>>empty()); - - /** - * @param - * @param - * @return an empty map - */ - @SuppressWarnings("unchecked") - public static HashPMap empty() { - return (HashPMap)EMPTY; } - - /** - * @param - * @param - * @param key - * @param value - * @return empty().plus(key, value) - */ - public static HashPMap singleton(final K key, final V value) { - return HashTreePMap.empty().plus(key, value); } - - /** - * @param - * @param - * @param map - * @return empty().plusAll(map) - */ - public static HashPMap from(final Map map) { - return HashTreePMap.empty().plusAll(map); } -} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java index d5a1ea7b2bb..5d3fcd44160 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java @@ -1,309 +1,248 @@ package kotlin.reflect.jvm.internal.pcollections; -import java.util.Iterator; -import java.util.Map.Entry; - - - - /** - * * A non-public utility class for persistent balanced tree maps with integer keys. - *

+ *

* To allow for efficiently increasing all keys above a certain value or decreasing * all keys below a certain value, the keys values are stored relative to their parent. * This makes this map a good backing for fast insertion and removal of indices in a * vector. - *

+ *

* This implementation is thread-safe except for its iterators. - *

+ *

* Other than that, this tree is based on the Glasgow Haskell Compiler's Data.Map implementation, * which in turn is based on "size balanced binary trees" as described by: - *

+ *

* Stephen Adams, "Efficient sets: a balancing act", * Journal of Functional Programming 3(4):553-562, October 1993, * http://www.swiss.ai.mit.edu/~adams/BB/. - *

+ *

* J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance", * SIAM journal of computing 2(1), March 1973. - * - * @author harold * - * @param + * @author harold */ -class IntTree { - // marker value: - static final IntTree EMPTYNODE = new IntTree(); - - private final long key; // we use longs so relative keys can express all ints - // (e.g. if this has key -10 and right has 'absolute' key MAXINT, - // then its relative key is MAXINT+10 which overflows) - // there might be some way to deal with this based on left-verse-right logic, - // but that sounds like a mess. - private final V value; // null value means this is empty node - private final IntTree left, right; - private final int size; - private IntTree() { - if(EMPTYNODE!=null) - throw new RuntimeException("empty constructor should only be used once"); - size = 0; - - key=0; value=null; left=null; right=null; - } - private IntTree(final long key, final V value, final IntTree left, final IntTree right) { - this.key = key; this.value = value; - this.left = left; this.right = right; - size = 1 + left.size + right.size; - } - - private IntTree withKey(final long newKey) { - if(size==0 || newKey==key) return this; - return new IntTree(newKey, value, left, right); } - - Iterator> iterator() { - return new EntryIterator(this); } - - int size() { - return size; } +final class IntTree { + // marker value: + static final IntTree EMPTYNODE = new IntTree(); - boolean containsKey(final long key) { - if(size==0) - return false; - if(key < this.key) - return left.containsKey(key-this.key); - if(key > this.key) - return right.containsKey(key-this.key); - // otherwise key==this.key: - return true; - } - - V get(final long key) { - if(size==0) - return null; - if(key < this.key) - return left.get(key-this.key); - if(key > this.key) - return right.get(key-this.key); - // otherwise key==this.key: - return value; - } + // we use longs so relative keys can express all ints + // (e.g. if this has key -10 and right has 'absolute' key MAXINT, + // then its relative key is MAXINT+10 which overflows) + // there might be some way to deal with this based on left-verse-right logic, + // but that sounds like a mess. + private final long key; + private final V value; // null value means this is empty node + private final IntTree left, right; + private final int size; - IntTree plus(final long key, final V value) { - if(size==0) - return new IntTree(key, value, this, this); - if(key < this.key) - return rebalanced(left.plus(key-this.key, value), right); - if(key > this.key) - return rebalanced(left, right.plus(key-this.key, value)); - // otherwise key==this.key, so we simply replace this, with no effect on balance: - if(value==this.value) - return this; - return new IntTree(key, value, left, right); - } + private IntTree() { + size = 0; + key = 0; + value = null; + left = null; + right = null; + } - IntTree minus(final long key) { - if(size==0) - return this; - if(key < this.key) - return rebalanced(left.minus(key-this.key), right); - if(key > this.key) - return rebalanced(left, right.minus(key-this.key)); + private IntTree(long key, V value, IntTree left, IntTree right) { + this.key = key; + this.value = value; + this.left = left; + this.right = right; + size = 1 + left.size + right.size; + } - // otherwise key==this.key, so we are killing this node: + private IntTree withKey(long newKey) { + if (size == 0 || newKey == key) return this; + return new IntTree(newKey, value, left, right); + } - if(left.size==0) // we can just become right node - // make key 'absolute': - return right.withKey(right.key+this.key); - if(right.size==0) // we can just become left node - return left.withKey(left.key+this.key); + boolean containsKey(long key) { + if (size == 0) + return false; + if (key < this.key) + return left.containsKey(key - this.key); + if (key > this.key) + return right.containsKey(key - this.key); + // otherwise key==this.key: + return true; + } - // otherwise replace this with the next key (i.e. the smallest key to the right): - - // TODO have minNode() instead of minKey to avoid having to call get() - // TODO get node from larger subtree, i.e. if left.size>right.size use left.maxNode() - // TODO have faster minusMin() instead of just using minus() - - long newKey = right.minKey() + this.key; - //(right.minKey() is relative to this; adding this.key makes it 'absolute' - // where 'absolute' really means relative to the parent of this) + V get(long key) { + if (size == 0) + return null; + if (key < this.key) + return left.get(key - this.key); + if (key > this.key) + return right.get(key - this.key); + // otherwise key==this.key: + return value; + } - V newValue = right.get(newKey-this.key); - // now that we've got the new stuff, take it out of the right subtree: - IntTree newRight = right.minus(newKey-this.key); + IntTree plus(long key, V value) { + if (size == 0) + return new IntTree(key, value, this, this); + if (key < this.key) + return rebalanced(left.plus(key - this.key, value), right); + if (key > this.key) + return rebalanced(left, right.plus(key - this.key, value)); + // otherwise key==this.key, so we simply replace this, with no effect on balance: + if (value == this.value) + return this; + return new IntTree(key, value, left, right); + } - // lastly, make the subtree keys relative to newKey (currently they are relative to this.key): - newRight = newRight.withKey( (newRight.key+this.key) - newKey ); - // left is definitely not empty: - IntTree newLeft = left.withKey( (left.key+this.key) - newKey ); - - return rebalanced(newKey, newValue, newLeft, newRight); - } - - /** - * Changes every key k>=key to k+delta. - * - * This method will create an _invalid_ tree if delta<0 - * and the distance between the smallest k>=key in this - * and the largest j changeKeysAbove(final long key, final int delta) { - if(size==0 || delta==0) - return this; + IntTree minus(long key) { + if (size == 0) + return this; + if (key < this.key) + return rebalanced(left.minus(key - this.key), right); + if (key > this.key) + return rebalanced(left, right.minus(key - this.key)); - if(this.key>=key) - // adding delta to this.key changes the keys of _all_ children of this, - // so we now need to un-change the children of this smaller than key, - // all of which are to the left. note that we still use the 'old' relative key...: - return new IntTree(this.key+delta, value, left.changeKeysBelow(key-this.key, -delta), right); + // otherwise key==this.key, so we are killing this node: - // otherwise, doesn't apply yet, look to the right: - IntTree newRight = right.changeKeysAbove(key-this.key, delta); - if(newRight==right) return this; - return new IntTree(this.key, value, left, newRight); - } - - /** - * Changes every key k0 - * and the distance between the largest k=key in this is delta or less. - * - * In other words, this method must not result in any overlap or change - * in the order of the keys in this, since the tree _structure_ is - * not being changed at all. - */ - IntTree changeKeysBelow(final long key, final int delta) { - if(size==0 || delta==0) - return this; + if (left.size == 0) // we can just become right node + // make key 'absolute': + return right.withKey(right.key + this.key); + if (right.size == 0) // we can just become left node + return left.withKey(left.key + this.key); - if(this.key(this.key+delta, value, left, right.changeKeysAbove(key-this.key, -delta)); + // otherwise replace this with the next key (i.e. the smallest key to the right): - // otherwise, doesn't apply yet, look to the left: - IntTree newLeft = left.changeKeysBelow(key-this.key, delta); - if(newLeft==left) return this; - return new IntTree(this.key, value, newLeft, right); - } - - // min key in this: - private long minKey() { - if(left.size==0) - return key; - // make key 'absolute' (i.e. relative to the parent of this): - return left.minKey() + this.key; - } + // TODO have minNode() instead of minKey to avoid having to call get() + // TODO get node from larger subtree, i.e. if left.size>right.size use left.maxNode() + // TODO have faster minusMin() instead of just using minus() - private IntTree rebalanced(final IntTree newLeft, final IntTree newRight) { - if(newLeft==left && newRight==right) - return this; // already balanced - return rebalanced(key, value, newLeft, newRight); - } + long newKey = right.minKey() + this.key; + //(right.minKey() is relative to this; adding this.key makes it 'absolute' + // where 'absolute' really means relative to the parent of this) - private static final int OMEGA = 5; - private static final int ALPHA = 2; - // rebalance a tree that is off-balance by at most 1: - private static IntTree rebalanced(final long key, final V value, - final IntTree left, final IntTree right) { - if(left.size + right.size > 1) { - if(left.size >= OMEGA*right.size) { // rotate to the right - IntTree ll = left.left, lr = left.right; - if(lr.size < ALPHA*ll.size) // single rotation - return new IntTree(left.key+key, left.value, - ll, - new IntTree(-left.key, value, - lr.withKey(lr.key+left.key), - right)); - else { // double rotation: - IntTree lrl = lr.left, lrr = lr.right; - return new IntTree(lr.key+left.key+key, lr.value, - new IntTree(-lr.key, left.value, - ll, - lrl.withKey(lrl.key+lr.key)), - new IntTree(-left.key-lr.key, value, - lrr.withKey(lrr.key+lr.key+left.key), - right)); - } - } - else if(right.size >= OMEGA*left.size) { // rotate to the left - IntTree rl = right.left, rr = right.right; - if(rl.size < ALPHA*rr.size) // single rotation - return new IntTree(right.key+key, right.value, - new IntTree(-right.key, value, - left, - rl.withKey(rl.key+right.key)), - rr); - else { // double rotation: - IntTree rll = rl.left, rlr = rl.right; - return new IntTree(rl.key+right.key+key, rl.value, - new IntTree(-right.key-rl.key, value, - left, - rll.withKey(rll.key+rl.key+right.key)), - new IntTree(-rl.key, right.value, - rlr.withKey(rlr.key+rl.key), - rr)); - } - } - } - // otherwise already balanced enough: - return new IntTree(key, value, left, right); - } + V newValue = right.get(newKey - this.key); + // now that we've got the new stuff, take it out of the right subtree: + IntTree newRight = right.minus(newKey - this.key); - -////entrySet().iterator() IMPLEMENTATION //// - // TODO make this a ListIterator? - private static final class EntryIterator implements Iterator> { - private PStack> stack = ConsPStack.empty(); //path of nonempty nodes - private int key = 0; // note we use _int_ here since this is a truly absolute key - - EntryIterator(final IntTree root) { - gotoMinOf(root); } - - public boolean hasNext() { - return stack.size()>0; } - - public Entry next() { - IntTree node = stack.get(0); - final Entry result = new SimpleImmutableEntry(key, node.value); - - // find next node. - // we've already done everything smaller, - // so try least larger node: - - if(node.right.size>0) // we can descend to the right - gotoMinOf(node.right); - - else // can't descend to the right -- try ascending to the right - while (true) { // find current node's least larger ancestor, if any - key -= node.key; // revert to parent's key - stack = stack.subList(1); // climb up to parent - // if parent was larger than child or there was no parent, we're done: - if(node.key<0 || stack.size()==0) - break; - // otherwise parent was smaller -- try its parent: - node = stack.get(0); - } - - return result; - } + // lastly, make the subtree keys relative to newKey (currently they are relative to this.key): + newRight = newRight.withKey((newRight.key + this.key) - newKey); + // left is definitely not empty: + IntTree newLeft = left.withKey((left.key + this.key) - newKey); - public void remove() { - throw new UnsupportedOperationException(); } + return rebalanced(newKey, newValue, newLeft, newRight); + } - // extend the stack to its least non-empty node: - private void gotoMinOf(IntTree node) { - while(node.size>0) { - stack = stack.plus(node); - key += node.key; - node = node.left; - } - } - } + /** + * Changes every key k>=key to k+delta. + *

+ * This method will create an _invalid_ tree if delta<0 + * and the distance between the smallest k>=key in this + * and the largest j + * In other words, this method must not result in any change + * in the order of the keys in this, since the tree structure is + * not being changed at all. + */ + IntTree changeKeysAbove(long key, int delta) { + if (size == 0 || delta == 0) + return this; + + if (this.key >= key) + // adding delta to this.key changes the keys of _all_ children of this, + // so we now need to un-change the children of this smaller than key, + // all of which are to the left. note that we still use the 'old' relative key...: + return new IntTree(this.key + delta, value, left.changeKeysBelow(key - this.key, -delta), right); + + // otherwise, doesn't apply yet, look to the right: + IntTree newRight = right.changeKeysAbove(key - this.key, delta); + if (newRight == right) return this; + return new IntTree(this.key, value, left, newRight); + } + + /** + * Changes every key k + * This method will create an _invalid_ tree if delta>0 + * and the distance between the largest k=key in this is delta or less. + *

+ * In other words, this method must not result in any overlap or change + * in the order of the keys in this, since the tree _structure_ is + * not being changed at all. + */ + IntTree changeKeysBelow(long key, int delta) { + if (size == 0 || delta == 0) + return this; + + if (this.key < key) + // adding delta to this.key changes the keys of _all_ children of this, + // so we now need to un-change the children of this larger than key, + // all of which are to the right. note that we still use the 'old' relative key...: + return new IntTree(this.key + delta, value, left, right.changeKeysAbove(key - this.key, -delta)); + + // otherwise, doesn't apply yet, look to the left: + IntTree newLeft = left.changeKeysBelow(key - this.key, delta); + if (newLeft == left) return this; + return new IntTree(this.key, value, newLeft, right); + } + + // min key in this: + private long minKey() { + if (left.size == 0) + return key; + // make key 'absolute' (i.e. relative to the parent of this): + return left.minKey() + this.key; + } + + private IntTree rebalanced(IntTree newLeft, IntTree newRight) { + if (newLeft == left && newRight == right) + return this; // already balanced + return rebalanced(key, value, newLeft, newRight); + } + + private static final int OMEGA = 5; + private static final int ALPHA = 2; + + // rebalance a tree that is off-balance by at most 1: + private static IntTree rebalanced(long key, V value, IntTree left, IntTree right) { + if (left.size + right.size > 1) { + if (left.size >= OMEGA * right.size) { // rotate to the right + IntTree ll = left.left, lr = left.right; + if (lr.size < ALPHA * ll.size) // single rotation + return new IntTree(left.key + key, left.value, + ll, + new IntTree(-left.key, value, + lr.withKey(lr.key + left.key), + right)); + else { // double rotation: + IntTree lrl = lr.left, lrr = lr.right; + return new IntTree(lr.key + left.key + key, lr.value, + new IntTree(-lr.key, left.value, + ll, + lrl.withKey(lrl.key + lr.key)), + new IntTree(-left.key - lr.key, value, + lrr.withKey(lrr.key + lr.key + left.key), + right)); + } + } else if (right.size >= OMEGA * left.size) { // rotate to the left + IntTree rl = right.left, rr = right.right; + if (rl.size < ALPHA * rr.size) // single rotation + return new IntTree(right.key + key, right.value, + new IntTree(-right.key, value, + left, + rl.withKey(rl.key + right.key)), + rr); + else { // double rotation: + IntTree rll = rl.left, rlr = rl.right; + return new IntTree(rl.key + right.key + key, rl.value, + new IntTree(-right.key - rl.key, value, + left, + rll.withKey(rll.key + rl.key + right.key)), + new IntTree(-rl.key, right.value, + rlr.withKey(rlr.key + rl.key), + rr)); + } + } + } + // otherwise already balanced enough: + return new IntTree(key, value, left, right); + } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java index 4c144faf378..169409aee9b 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java @@ -1,163 +1,52 @@ package kotlin.reflect.jvm.internal.pcollections; -import java.util.AbstractMap; -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - - - - /** - * * An efficient persistent map from integer keys to non-null values. - *

+ *

* Iteration occurs in the integer order of the keys. - *

- * This implementation is thread-safe (assuming Java's AbstractMap and AbstractSet are thread-safe), - * although its iterators may not be. - *

+ *

+ * This implementation is thread-safe, although its iterators may not be. + *

* The balanced tree is based on the Glasgow Haskell Compiler's Data.Map implementation, * which in turn is based on "size balanced binary trees" as described by: - *

+ *

* Stephen Adams, "Efficient sets: a balancing act", * Journal of Functional Programming 3(4):553-562, October 1993, * http://www.swiss.ai.mit.edu/~adams/BB/. - *

+ *

* J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance", * SIAM journal of computing 2(1), March 1973. - * - * @author harold * - * @param + * @author harold */ -public final class IntTreePMap extends AbstractMap implements PMap { -//// STATIC FACTORY METHODS //// - private static final IntTreePMap EMPTY = new IntTreePMap(IntTree.EMPTYNODE); +public final class IntTreePMap { + private static final IntTreePMap EMPTY = new IntTreePMap(IntTree.EMPTYNODE); - /** - * @param - * @return an empty map - */ - @SuppressWarnings("unchecked") - public static IntTreePMap empty() { - return (IntTreePMap)EMPTY; } - - /** - * @param - * @param key - * @param value - * @return empty().plus(key, value) - */ - public static IntTreePMap singleton(final Integer key, final V value) { - return IntTreePMap.empty().plus(key, value); } - - /** - * @param - * @param map - * @return empty().plusAll(map) - */ - @SuppressWarnings("unchecked") - public static IntTreePMap from(final Map map) { - if(map instanceof IntTreePMap) - return (IntTreePMap)map; //(actually we only know it's IntTreePMap) - // but that's good enough for an immutable - // (i.e. we can't mess someone else up by adding the wrong type to it) - return IntTreePMap.empty().plusAll(map); } - + @SuppressWarnings("unchecked") + public static IntTreePMap empty() { + return (IntTreePMap) EMPTY; + } -//// PRIVATE CONSTRUCTORS //// - private final IntTree root; - // not externally instantiable (or subclassable): - private IntTreePMap(final IntTree root) { - this.root = root; } - private IntTreePMap withRoot(final IntTree root) { - if(root==this.root) return this; - return new IntTreePMap(root); } - + private final IntTree root; -//// UNINHERITED METHODS OF IntTreePMap //// - IntTreePMap withKeysChangedAbove(final int key, final int delta) { - // TODO check preconditions of changeKeysAbove() - // TODO make public? - return withRoot( root.changeKeysAbove(key, delta) ); - } - - IntTreePMap withKeysChangedBelow(final int key, final int delta) { - // TODO check preconditions of changeKeysAbove() - // TODO make public? - return withRoot( root.changeKeysBelow(key, delta) ); - } - -//// REQUIRED METHODS FROM AbstractMap //// - // this cache variable is thread-safe, since assignment in Java is atomic: - private Set> entrySet = null; - @Override - public Set> entrySet() { - if(entrySet==null) - entrySet = new AbstractSet>() { - // REQUIRED METHODS OF AbstractSet // - @Override - public int size() { // same as Map - return IntTreePMap.this.size(); } - @Override - public Iterator> iterator() { - return root.iterator(); } - // OVERRIDDEN METHODS OF AbstractSet // - @Override - public boolean contains(final Object e) { - if(!(e instanceof Entry)) - return false; - V value = get(((Entry)e).getKey()); - return value!=null && value.equals(((Entry)e).getValue()); - } - }; - return entrySet; - } + private IntTreePMap(IntTree root) { + this.root = root; + } - -//// OVERRIDDEN METHODS FROM AbstractMap //// - @Override - public int size() { - return root.size(); } + private IntTreePMap withRoot(IntTree root) { + if (root == this.root) return this; + return new IntTreePMap(root); + } - @Override - public boolean containsKey(final Object key) { - if(!(key instanceof Integer)) - return false; - return root.containsKey((Integer)key); - } - - @Override - public V get(final Object key) { - if(!(key instanceof Integer)) - return null; - return root.get((Integer)key); - } + public V get(int key) { + return root.get(key); + } - -//// IMPLEMENTED METHODS OF PMap//// - public IntTreePMap plus(final Integer key, final V value) { - return withRoot( root.plus(key, value) ); } - - public IntTreePMap minus(final Object key) { - if(!(key instanceof Integer)) return this; - return withRoot( root.minus((Integer)key) ); } - - public IntTreePMap plusAll(final Map map) { - IntTree root = this.root; - for(Entry entry : map.entrySet()) - root = root.plus(entry.getKey(), entry.getValue()); - return withRoot(root); - } + public IntTreePMap plus(int key, V value) { + return withRoot(root.plus(key, value)); + } - public IntTreePMap minusAll(final Collection keys) { - IntTree root = this.root; - for(Object key : keys) - if(key instanceof Integer) - root = root.minus((Integer)key); - return withRoot(root); - } + public IntTreePMap minus(int key) { + return withRoot(root.minus(key)); + } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PCollection.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PCollection.java deleted file mode 100644 index 333acc4ca15..00000000000 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PCollection.java +++ /dev/null @@ -1,47 +0,0 @@ -package kotlin.reflect.jvm.internal.pcollections; - -import java.util.Collection; - -/** - * - * An immutable, persistent collection of non-null elements of type E. - * - * @author harold - * - * @param - */ -public interface PCollection extends Collection { - - /** - * @param e non-null - * @return a collection which contains e and all of the elements of this - */ - public PCollection plus(E e); - - /** - * @param list contains no null elements - * @return a collection which contains all of the elements of list and this - */ - public PCollection plusAll(Collection list); - - /** - * @param e - * @return this with a single instance of e removed, if e is in this - */ - public PCollection minus(Object e); - - /** - * @param list - * @return this with all elements of list completely removed - */ - public PCollection minusAll(Collection list); - - // TODO public PCollection retainingAll(Collection list); - - @Deprecated boolean add(E o); - @Deprecated boolean remove(Object o); - @Deprecated boolean addAll(Collection c); - @Deprecated boolean removeAll(Collection c); - @Deprecated boolean retainAll(Collection c); - @Deprecated void clear(); -} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java index bdfd4f54896..e8e1c2c4217 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java @@ -1,45 +1,14 @@ package kotlin.reflect.jvm.internal.pcollections; -import java.util.Collection; -import java.util.Map; - /** - * * An immutable, persistent map from non-null keys of type K to non-null values of type V. - * - * @author harold * - * @param - * @param + * @author harold */ -public interface PMap extends Map { - /** - * @param key non-null - * @param value non-null - * @return a map with the mappings of this but with key mapped to value - */ - public PMap plus(K key, V value); - - /** - * @param map - * @return this combined with map, with map's mappings used for any keys in both map and this - */ - public PMap plusAll(Map map); - - /** - * @param key - * @return a map with the mappings of this but with no value for key - */ - public PMap minus(Object key); - - /** - * @param keys - * @return a map with the mappings of this but with no value for any element of keys - */ - public PMap minusAll(Collection keys); - - @Deprecated V put(K k, V v); - @Deprecated V remove(Object k); - @Deprecated void putAll(Map m); - @Deprecated void clear(); +public interface PMap { + public PMap plus(K key, V value); + + public PMap minus(Object key); + + V get(Object key); } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PSequence.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PSequence.java deleted file mode 100644 index 3be82dcec0f..00000000000 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PSequence.java +++ /dev/null @@ -1,69 +0,0 @@ -package kotlin.reflect.jvm.internal.pcollections; - -import java.util.Collection; -import java.util.List; - -/** - * - * An immutable, persistent indexed collection. - * - * @author harold - * - * @param - */ -public interface PSequence extends PCollection, List { - - //@Override - public PSequence plus(E e); - - //@Override - public PSequence plusAll(Collection list); - - /** - * @param i - * @param e - * @return a sequence consisting of the elements of this with e replacing the element at index i. - * @throws IndexOutOfBOundsException if i<0 || i>=this.size() - */ - public PSequence with(int i, E e); - - /** - * @param i - * @param e non-null - * @return a sequence consisting of the elements of this with e inserted at index i. - * @throws IndexOutOfBOundsException if i<0 || i>this.size() - */ - public PSequence plus(int i, E e); - - /** - * @param i - * @param list - * @return a sequence consisting of the elements of this with list inserted at index i. - * @throws IndexOutOfBOundsException if i<0 || i>this.size() - */ - public PSequence plusAll(int i, Collection list); - - /** - * Returns a sequence consisting of the elements of this without the first occurrence of e. - */ - //@Override - public PSequence minus(Object e); - - //@Override - public PSequence minusAll(Collection list); - - /** - * @param i - * @return a sequence consisting of the elements of this with the element at index i removed. - * @throws IndexOutOfBOundsException if i<0 || i>=this.size() - */ - public PSequence minus(int i); - - //@Override - public PSequence subList(int start, int end); - - @Deprecated boolean addAll(int index, Collection c); - @Deprecated E set(int index, E element); - @Deprecated void add(int index, E element); - @Deprecated E remove(int index); -} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java index ca68a69360e..5b52152671a 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java @@ -1,53 +1,14 @@ package kotlin.reflect.jvm.internal.pcollections; -import java.util.Collection; - /** - * * An immutable, persistent stack. - * - * @author harold * - * @param + * @author harold */ -public interface PStack extends PSequence { - - /** - * Returns a stack consisting of the elements of this with e prepended. - */ - //@Override - public PStack plus(E e); - - /** - * Returns a stack consisting of the elements of this with list prepended in reverse. - */ - //@Override - public PStack plusAll(Collection list); - - //@Override - public PStack with(int i, E e); - - //@Override - public PStack plus(int i, E e); - - //@Override - public PStack plusAll(int i, Collection list); - - //@Override - public PStack minus(Object e); - - //@Override - public PStack minusAll(Collection list); +public interface PStack extends Iterable { + PStack plus(E e); - //@Override - public PStack minus(int i); + PStack minus(int i); - //@Override - public PStack subList(int start, int end); - - /** - * @param start - * @return subList(start,this.size()) - */ - public PStack subList(int start); + int size(); } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java index 71452649e25..ae79bc2bb6c 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java @@ -1,12 +1,9 @@ package kotlin.reflect.jvm.internal.pcollections; import java.util.Map; -import java.util.Map.Entry; - /** - * (Taken from Java 6 code, so pcollections can be Java 5-compatible.) - *

+ *

* An Entry maintaining an immutable key and value. This class * does not support method setValue. This class may be * convenient in methods that return thread-safe snapshots of @@ -14,129 +11,119 @@ import java.util.Map.Entry; * * @since 1.6 */ -/*public*/ final class SimpleImmutableEntry - implements Map.Entry, java.io.Serializable -{ - private static final long serialVersionUID = 7138329143949025153L; +final class SimpleImmutableEntry implements Map.Entry, java.io.Serializable { + private static final long serialVersionUID = 7138329143949025153L; - private final K key; - private final V value; + private final K key; + private final V value; - /** - * Creates an entry representing a mapping from the specified - * key to the specified value. - * - * @param key the key represented by this entry - * @param value the value represented by this entry - */ - public SimpleImmutableEntry(K key, V value) { - this.key = key; - this.value = value; - } + /** + * Creates an entry representing a mapping from the specified + * key to the specified value. + * + * @param key the key represented by this entry + * @param value the value represented by this entry + */ + public SimpleImmutableEntry(K key, V value) { + this.key = key; + this.value = value; + } - /** - * Creates an entry representing the same mapping as the - * specified entry. - * - * @param entry the entry to copy - */ - public SimpleImmutableEntry(Entry entry) { - this.key = entry.getKey(); - this.value = entry.getValue(); - } + /** + * Returns the key corresponding to this entry. + * + * @return the key corresponding to this entry + */ + @Override + public K getKey() { + return key; + } - /** - * Returns the key corresponding to this entry. - * - * @return the key corresponding to this entry - */ - public K getKey() { - return key; - } + /** + * Returns the value corresponding to this entry. + * + * @return the value corresponding to this entry + */ + @Override + public V getValue() { + return value; + } - /** - * Returns the value corresponding to this entry. - * - * @return the value corresponding to this entry - */ - public V getValue() { - return value; - } + /** + * Replaces the value corresponding to this entry with the specified + * value (optional operation). This implementation simply throws + * UnsupportedOperationException, as this class implements + * an immutable map entry. + * + * @param value new value to be stored in this entry + * @return (Does not return) + * @throws UnsupportedOperationException always + */ + @Override + public V setValue(V value) { + throw new UnsupportedOperationException(); + } - /** - * Replaces the value corresponding to this entry with the specified - * value (optional operation). This implementation simply throws - * UnsupportedOperationException, as this class implements - * an immutable map entry. - * - * @param value new value to be stored in this entry - * @return (Does not return) - * @throws UnsupportedOperationException always - */ - public V setValue(V value) { - throw new UnsupportedOperationException(); - } + /** + * Compares the specified object with this entry for equality. + * Returns {@code true} if the given object is also a map entry and + * the two entries represent the same mapping. More formally, two + * entries {@code e1} and {@code e2} represent the same mapping + * if

+     *   (e1.getKey()==null ?
+     *    e2.getKey()==null :
+     *    e1.getKey().equals(e2.getKey()))
+     *   &&
+     *   (e1.getValue()==null ?
+     *    e2.getValue()==null :
+     *    e1.getValue().equals(e2.getValue()))
+ * This ensures that the {@code equals} method works properly across + * different implementations of the {@code Map.Entry} interface. + * + * @param o object to be compared for equality with this map entry + * @return {@code true} if the specified object is equal to this map + * entry + * @see #hashCode + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry) o; + return eq(key, e.getKey()) && eq(value, e.getValue()); + } - /** - * Compares the specified object with this entry for equality. - * Returns {@code true} if the given object is also a map entry and - * the two entries represent the same mapping. More formally, two - * entries {@code e1} and {@code e2} represent the same mapping - * if
-	 *   (e1.getKey()==null ?
-	 *    e2.getKey()==null :
-	 *    e1.getKey().equals(e2.getKey()))
-	 *   &&
-	 *   (e1.getValue()==null ?
-	 *    e2.getValue()==null :
-	 *    e1.getValue().equals(e2.getValue()))
- * This ensures that the {@code equals} method works properly across - * different implementations of the {@code Map.Entry} interface. - * - * @param o object to be compared for equality with this map entry - * @return {@code true} if the specified object is equal to this map - * entry - * @see #hashCode - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - return eq(key, e.getKey()) && eq(value, e.getValue()); - } + /** + * Returns the hash code value for this map entry. The hash code + * of a map entry {@code e} is defined to be:
+     *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+     *   (e.getValue()==null ? 0 : e.getValue().hashCode())
+ * This ensures that {@code e1.equals(e2)} implies that + * {@code e1.hashCode()==e2.hashCode()} for any two Entries + * {@code e1} and {@code e2}, as required by the general + * contract of {@link Object#hashCode}. + * + * @return the hash code value for this map entry + * @see #equals + */ + @Override + public int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } - /** - * Returns the hash code value for this map entry. The hash code - * of a map entry {@code e} is defined to be:
-	 *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
-	 *   (e.getValue()==null ? 0 : e.getValue().hashCode())
- * This ensures that {@code e1.equals(e2)} implies that - * {@code e1.hashCode()==e2.hashCode()} for any two Entries - * {@code e1} and {@code e2}, as required by the general - * contract of {@link Object#hashCode}. - * - * @return the hash code value for this map entry - * @see #equals - */ - @Override - public int hashCode() { - return (key == null ? 0 : key.hashCode()) ^ - (value == null ? 0 : value.hashCode()); - } - - /** - * Returns a String representation of this map entry. This - * implementation returns the string representation of this - * entry's key followed by the equals character ("=") - * followed by the string representation of this entry's value. - * - * @return a String representation of this map entry - */ - @Override - public String toString() { - return key + "=" + value; - } + /** + * Returns a String representation of this map entry. This + * implementation returns the string representation of this + * entry's key followed by the equals character ("=") + * followed by the string representation of this entry's value. + * + * @return a String representation of this map entry + */ + @Override + public String toString() { + return key + "=" + value; + } /** * Utility method for SimpleEntry and SimpleImmutableEntry. From fca9a0bca2713a52180261be61d9003a391e0ebd Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 9 Jun 2014 22:44:27 +0400 Subject: [PATCH 16/38] Delete unneeded interface dependencies of HashPMap To reduce class count and to avoid unneeded invokeinterface's --- .../jvm/internal/pcollections/ConsPStack.java | 5 +- .../jvm/internal/pcollections/HashPMap.java | 31 ++-- .../jvm/internal/pcollections/MapEntry.java | 47 ++++++ .../jvm/internal/pcollections/PMap.java | 14 -- .../jvm/internal/pcollections/PStack.java | 14 -- .../pcollections/SimpleImmutableEntry.java | 135 ------------------ 6 files changed, 61 insertions(+), 185 deletions(-) create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java delete mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java delete mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java delete mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java index 90ea3b6dee2..93cb7996f30 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java @@ -11,7 +11,7 @@ import java.util.NoSuchElementException; * * @author harold */ -public final class ConsPStack implements PStack { +public final class ConsPStack implements Iterable { private static final ConsPStack EMPTY = new ConsPStack(); @SuppressWarnings("unchecked") @@ -48,7 +48,6 @@ public final class ConsPStack implements PStack { return listIterator(0); } - @Override public int size() { return size; } @@ -111,7 +110,6 @@ public final class ConsPStack implements PStack { }; } - @Override public ConsPStack plus(E e) { return new ConsPStack(e, this); } @@ -126,7 +124,6 @@ public final class ConsPStack implements PStack { return new ConsPStack(first, newRest); } - @Override public ConsPStack minus(int i) { return minus(get(i)); } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java index 36c6abc287e..2989de823e6 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java @@ -1,7 +1,5 @@ package kotlin.reflect.jvm.internal.pcollections; -import static java.util.Map.Entry; - /** * A persistent map from non-null keys to non-null values. *

@@ -13,18 +11,18 @@ import static java.util.Map.Entry; * * @author harold */ -public final class HashPMap implements PMap { - public static final HashPMap EMPTY = new HashPMap(IntTreePMap.>>empty(), 0); +public final class HashPMap { + private static final HashPMap EMPTY = new HashPMap(IntTreePMap.>>empty(), 0); @SuppressWarnings("unchecked") public static HashPMap empty() { return (HashPMap) HashPMap.EMPTY; } - private final IntTreePMap>> intMap; + private final IntTreePMap>> intMap; private final int size; - private HashPMap(IntTreePMap>> intMap, int size) { + private HashPMap(IntTreePMap>> intMap, int size) { this.intMap = intMap; this.size = size; } @@ -37,28 +35,25 @@ public final class HashPMap implements PMap { return keyIndexIn(getEntries(key.hashCode()), key) != -1; } - @Override public V get(Object key) { - PStack> entries = getEntries(key.hashCode()); - for (Entry entry : entries) + ConsPStack> entries = getEntries(key.hashCode()); + for (MapEntry entry : entries) if (entry.getKey().equals(key)) return entry.getValue(); return null; } - @Override public HashPMap plus(K key, V value) { - PStack> entries = getEntries(key.hashCode()); + ConsPStack> entries = getEntries(key.hashCode()); int size0 = entries.size(); int i = keyIndexIn(entries, key); if (i != -1) entries = entries.minus(i); - entries = entries.plus(new SimpleImmutableEntry(key, value)); + entries = entries.plus(new MapEntry(key, value)); return new HashPMap(intMap.plus(key.hashCode(), entries), size - size0 + entries.size()); } - @Override public HashPMap minus(Object key) { - PStack> entries = getEntries(key.hashCode()); + ConsPStack> entries = getEntries(key.hashCode()); int i = keyIndexIn(entries, key); if (i == -1) // key not in this return this; @@ -69,15 +64,15 @@ public final class HashPMap implements PMap { return new HashPMap(intMap.plus(key.hashCode(), entries), size - 1); } - private PStack> getEntries(int hash) { - PStack> entries = intMap.get(hash); + private ConsPStack> getEntries(int hash) { + ConsPStack> entries = intMap.get(hash); if (entries == null) return ConsPStack.empty(); return entries; } - private static int keyIndexIn(PStack> entries, Object key) { + private static int keyIndexIn(ConsPStack> entries, Object key) { int i = 0; - for (Entry entry : entries) { + for (MapEntry entry : entries) { if (entry.getKey().equals(key)) return i; i++; diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java new file mode 100644 index 00000000000..9251bdb4e6b --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java @@ -0,0 +1,47 @@ +package kotlin.reflect.jvm.internal.pcollections; + +/** + *

+ * An Entry maintaining an immutable key and value. This class + * does not support method setValue. This class may be + * convenient in methods that return thread-safe snapshots of + * key-value mappings. + */ +final class MapEntry implements java.io.Serializable { + private static final long serialVersionUID = 7138329143949025153L; + + private final K key; + private final V value; + + public MapEntry(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof MapEntry)) return false; + MapEntry e = (MapEntry) o; + return (key == null ? e.key == null : key.equals(e.key)) && + (value == null ? e.value == null : value.equals(e.value)); + } + + @Override + public int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + @Override + public String toString() { + return key + "=" + value; + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java deleted file mode 100644 index e8e1c2c4217..00000000000 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PMap.java +++ /dev/null @@ -1,14 +0,0 @@ -package kotlin.reflect.jvm.internal.pcollections; - -/** - * An immutable, persistent map from non-null keys of type K to non-null values of type V. - * - * @author harold - */ -public interface PMap { - public PMap plus(K key, V value); - - public PMap minus(Object key); - - V get(Object key); -} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java deleted file mode 100644 index 5b52152671a..00000000000 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/PStack.java +++ /dev/null @@ -1,14 +0,0 @@ -package kotlin.reflect.jvm.internal.pcollections; - -/** - * An immutable, persistent stack. - * - * @author harold - */ -public interface PStack extends Iterable { - PStack plus(E e); - - PStack minus(int i); - - int size(); -} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java deleted file mode 100644 index ae79bc2bb6c..00000000000 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/SimpleImmutableEntry.java +++ /dev/null @@ -1,135 +0,0 @@ -package kotlin.reflect.jvm.internal.pcollections; - -import java.util.Map; - -/** - *

- * An Entry maintaining an immutable key and value. This class - * does not support method setValue. This class may be - * convenient in methods that return thread-safe snapshots of - * key-value mappings. - * - * @since 1.6 - */ -final class SimpleImmutableEntry implements Map.Entry, java.io.Serializable { - private static final long serialVersionUID = 7138329143949025153L; - - private final K key; - private final V value; - - /** - * Creates an entry representing a mapping from the specified - * key to the specified value. - * - * @param key the key represented by this entry - * @param value the value represented by this entry - */ - public SimpleImmutableEntry(K key, V value) { - this.key = key; - this.value = value; - } - - /** - * Returns the key corresponding to this entry. - * - * @return the key corresponding to this entry - */ - @Override - public K getKey() { - return key; - } - - /** - * Returns the value corresponding to this entry. - * - * @return the value corresponding to this entry - */ - @Override - public V getValue() { - return value; - } - - /** - * Replaces the value corresponding to this entry with the specified - * value (optional operation). This implementation simply throws - * UnsupportedOperationException, as this class implements - * an immutable map entry. - * - * @param value new value to be stored in this entry - * @return (Does not return) - * @throws UnsupportedOperationException always - */ - @Override - public V setValue(V value) { - throw new UnsupportedOperationException(); - } - - /** - * Compares the specified object with this entry for equality. - * Returns {@code true} if the given object is also a map entry and - * the two entries represent the same mapping. More formally, two - * entries {@code e1} and {@code e2} represent the same mapping - * if

-     *   (e1.getKey()==null ?
-     *    e2.getKey()==null :
-     *    e1.getKey().equals(e2.getKey()))
-     *   &&
-     *   (e1.getValue()==null ?
-     *    e2.getValue()==null :
-     *    e1.getValue().equals(e2.getValue()))
- * This ensures that the {@code equals} method works properly across - * different implementations of the {@code Map.Entry} interface. - * - * @param o object to be compared for equality with this map entry - * @return {@code true} if the specified object is equal to this map - * entry - * @see #hashCode - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry) o; - return eq(key, e.getKey()) && eq(value, e.getValue()); - } - - /** - * Returns the hash code value for this map entry. The hash code - * of a map entry {@code e} is defined to be:
-     *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
-     *   (e.getValue()==null ? 0 : e.getValue().hashCode())
- * This ensures that {@code e1.equals(e2)} implies that - * {@code e1.hashCode()==e2.hashCode()} for any two Entries - * {@code e1} and {@code e2}, as required by the general - * contract of {@link Object#hashCode}. - * - * @return the hash code value for this map entry - * @see #equals - */ - @Override - public int hashCode() { - return (key == null ? 0 : key.hashCode()) ^ - (value == null ? 0 : value.hashCode()); - } - - /** - * Returns a String representation of this map entry. This - * implementation returns the string representation of this - * entry's key followed by the equals character ("=") - * followed by the string representation of this entry's value. - * - * @return a String representation of this map entry - */ - @Override - public String toString() { - return key + "=" + value; - } - - /** - * Utility method for SimpleEntry and SimpleImmutableEntry. - * Test for equality, checking for nulls. - */ - private static boolean eq(Object o1, Object o2) { - return o1 == null ? o2 == null : o1.equals(o2); - } -} From 862a785c11076ec9d6cccac85b65dabfd1faeb4d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 9 Jun 2014 23:04:47 +0400 Subject: [PATCH 17/38] Use pcollections' HashPMap instead of ConcurrentHashMap in reflection --- core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt index b1ed0ac560a..cf150b786b3 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -18,6 +18,7 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.Method import java.util.concurrent.ConcurrentHashMap +import kotlin.reflect.jvm.internal.pcollections.HashPMap // TODO: use stdlib? suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") @@ -47,13 +48,13 @@ private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: // TODO: should use weak references -private val foreignKClasses: MutableMap, KClassImpl<*>> = ConcurrentHashMap() +private var foreignKClasses = HashPMap.empty, KClassImpl<*>>()!! fun foreignKotlinClass(jClass: Class): KClassImpl { val cached = foreignKClasses[jClass] as? KClassImpl if (cached != null) return cached val result = KClassImpl(jClass) - foreignKClasses.put(jClass, result) + foreignKClasses = foreignKClasses.plus(jClass, result)!! return result } From 41aa12d24968193e67961e08cc41f3d896c61dcf Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 10 Jun 2014 19:13:51 +0400 Subject: [PATCH 18/38] Remove unneeded dependency on ListIterator in ConsPStack --- .../jvm/internal/pcollections/ConsPStack.java | 52 ++++--------------- .../internal/pcollections/IntTreePMap.java | 2 +- 2 files changed, 10 insertions(+), 44 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java index 93cb7996f30..91fef90dc82 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java @@ -1,7 +1,6 @@ package kotlin.reflect.jvm.internal.pcollections; import java.util.Iterator; -import java.util.ListIterator; import java.util.NoSuchElementException; /** @@ -11,7 +10,7 @@ import java.util.NoSuchElementException; * * @author harold */ -public final class ConsPStack implements Iterable { +final class ConsPStack implements Iterable { private static final ConsPStack EMPTY = new ConsPStack(); @SuppressWarnings("unchecked") @@ -36,8 +35,10 @@ public final class ConsPStack implements Iterable { } public E get(int index) { + if (index < 0 || index > size) throw new IndexOutOfBoundsException(); + try { - return listIterator(index).next(); + return iterator(index).next(); } catch (NoSuchElementException e) { throw new IndexOutOfBoundsException("Index: " + index); } @@ -45,18 +46,15 @@ public final class ConsPStack implements Iterable { @Override public Iterator iterator() { - return listIterator(0); + return iterator(0); } public int size() { return size; } - public ListIterator listIterator(final int index) { - if (index < 0 || index > size) throw new IndexOutOfBoundsException(); - - return new ListIterator() { - int i = index; + private Iterator iterator(final int index) { + return new Iterator() { ConsPStack next = subList(index); @Override @@ -64,21 +62,6 @@ public final class ConsPStack implements Iterable { return next.size > 0; } - @Override - public boolean hasPrevious() { - return i > 0; - } - - @Override - public int nextIndex() { - return index; - } - - @Override - public int previousIndex() { - return index - 1; - } - @Override public E next() { E e = next.first; @@ -86,27 +69,10 @@ public final class ConsPStack implements Iterable { return e; } - @Override - public E previous() { - System.err.println("ConsPStack.listIterator().previous() is inefficient, don't use it!"); - next = subList(index - 1); // go from beginning... - return next.first; - } - - @Override - public void add(E o) { - throw new UnsupportedOperationException(); - } - @Override public void remove() { throw new UnsupportedOperationException(); } - - @Override - public void set(E o) { - throw new UnsupportedOperationException(); - } }; } @@ -114,7 +80,7 @@ public final class ConsPStack implements Iterable { return new ConsPStack(e, this); } - public ConsPStack minus(Object e) { + private ConsPStack minus(Object e) { if (size == 0) return this; if (first.equals(e)) // found it return rest; // don't recurse (only remove one) @@ -128,7 +94,7 @@ public final class ConsPStack implements Iterable { return minus(get(i)); } - public ConsPStack subList(int start) { + private ConsPStack subList(int start) { if (start < 0 || start > size) throw new IndexOutOfBoundsException(); if (start == 0) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java index 169409aee9b..9a77bb2f5b8 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java @@ -19,7 +19,7 @@ package kotlin.reflect.jvm.internal.pcollections; * * @author harold */ -public final class IntTreePMap { +final class IntTreePMap { private static final IntTreePMap EMPTY = new IntTreePMap(IntTree.EMPTYNODE); @SuppressWarnings("unchecked") From b00022ef1c821c615c34b13f0460220b3e6b0e0b Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 25 Jun 2014 20:08:23 +0400 Subject: [PATCH 19/38] Add JetBrains license to HashPMap, remove obsolete author tags and javadocs --- .../jvm/internal/pcollections/ConsPStack.java | 18 +++++++++-- .../jvm/internal/pcollections/HashPMap.java | 24 +++++++++----- .../jvm/internal/pcollections/IntTree.java | 16 ++++++++++ .../internal/pcollections/IntTreePMap.java | 32 +++++++++---------- .../jvm/internal/pcollections/MapEntry.java | 23 +++++++++---- 5 files changed, 80 insertions(+), 33 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java index 91fef90dc82..a541e1e9206 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/ConsPStack.java @@ -1,3 +1,19 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal.pcollections; import java.util.Iterator; @@ -7,8 +23,6 @@ import java.util.NoSuchElementException; * A simple persistent stack of non-null values. *

* This implementation is thread-safe, although its iterators may not be. - * - * @author harold */ final class ConsPStack implements Iterable { private static final ConsPStack EMPTY = new ConsPStack(); diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java index 2989de823e6..eae81f149ea 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java @@ -1,15 +1,23 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal.pcollections; /** * A persistent map from non-null keys to non-null values. - *

- * This map uses a given integer map to map hashcodes to lists of elements - * with the same hashcode. Thus if all elements have the same hashcode, performance - * is reduced to that of an association list. - *

- * This implementation is thread-safe, although its iterators may not be. - * - * @author harold */ public final class HashPMap { private static final HashPMap EMPTY = new HashPMap(IntTreePMap.>>empty(), 0); diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java index 5d3fcd44160..d39167fedc1 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java @@ -1,3 +1,19 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal.pcollections; /** diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java index 9a77bb2f5b8..040f5464b43 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java @@ -1,23 +1,23 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal.pcollections; /** * An efficient persistent map from integer keys to non-null values. - *

- * Iteration occurs in the integer order of the keys. - *

- * This implementation is thread-safe, although its iterators may not be. - *

- * The balanced tree is based on the Glasgow Haskell Compiler's Data.Map implementation, - * which in turn is based on "size balanced binary trees" as described by: - *

- * Stephen Adams, "Efficient sets: a balancing act", - * Journal of Functional Programming 3(4):553-562, October 1993, - * http://www.swiss.ai.mit.edu/~adams/BB/. - *

- * J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance", - * SIAM journal of computing 2(1), March 1973. - * - * @author harold */ final class IntTreePMap { private static final IntTreePMap EMPTY = new IntTreePMap(IntTree.EMPTYNODE); diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java index 9251bdb4e6b..ccfa49a0878 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java @@ -1,12 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal.pcollections; -/** - *

- * An Entry maintaining an immutable key and value. This class - * does not support method setValue. This class may be - * convenient in methods that return thread-safe snapshots of - * key-value mappings. - */ final class MapEntry implements java.io.Serializable { private static final long serialVersionUID = 7138329143949025153L; From 47b08af66cbf8b1861de44ffcb146f687ade6f6a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 25 Jun 2014 20:12:34 +0400 Subject: [PATCH 20/38] Inline HashPMap entry's getter methods --- .../jvm/internal/pcollections/HashPMap.java | 6 +++--- .../jvm/internal/pcollections/MapEntry.java | 15 +++------------ 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java index eae81f149ea..6909aa304c6 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java @@ -46,8 +46,8 @@ public final class HashPMap { public V get(Object key) { ConsPStack> entries = getEntries(key.hashCode()); for (MapEntry entry : entries) - if (entry.getKey().equals(key)) - return entry.getValue(); + if (entry.key.equals(key)) + return entry.value; return null; } @@ -81,7 +81,7 @@ public final class HashPMap { private static int keyIndexIn(ConsPStack> entries, Object key) { int i = 0; for (MapEntry entry : entries) { - if (entry.getKey().equals(key)) + if (entry.key.equals(key)) return i; i++; } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java index ccfa49a0878..08d1b8288c9 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/MapEntry.java @@ -19,22 +19,14 @@ package kotlin.reflect.jvm.internal.pcollections; final class MapEntry implements java.io.Serializable { private static final long serialVersionUID = 7138329143949025153L; - private final K key; - private final V value; + public final K key; + public final V value; public MapEntry(K key, V value) { this.key = key; this.value = value; } - public K getKey() { - return key; - } - - public V getValue() { - return value; - } - @Override public boolean equals(Object o) { if (!(o instanceof MapEntry)) return false; @@ -45,8 +37,7 @@ final class MapEntry implements java.io.Serializable { @Override public int hashCode() { - return (key == null ? 0 : key.hashCode()) ^ - (value == null ? 0 : value.hashCode()); + return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } @Override From a86cfdc5de2c067b0d9abcf201eea66378d2a889 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 25 Jun 2014 19:55:27 +0400 Subject: [PATCH 21/38] Add some simple tests on HashPMap --- .../codegen/boxWithStdlib/hashPMap/empty.kt | 22 +++++++++ .../boxWithStdlib/hashPMap/manyNumbers.kt | 47 +++++++++++++++++++ .../hashPMap/rewriteWithDifferent.kt | 28 +++++++++++ .../hashPMap/rewriteWithEqual.kt | 28 +++++++++++ .../boxWithStdlib/hashPMap/simplePlusGet.kt | 24 ++++++++++ .../boxWithStdlib/hashPMap/simplePlusMinus.kt | 23 +++++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 41 +++++++++++++++- 7 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/hashPMap/empty.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/hashPMap/manyNumbers.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithDifferent.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithEqual.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusGet.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusMinus.kt diff --git a/compiler/testData/codegen/boxWithStdlib/hashPMap/empty.kt b/compiler/testData/codegen/boxWithStdlib/hashPMap/empty.kt new file mode 100644 index 00000000000..4c91756b263 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/hashPMap/empty.kt @@ -0,0 +1,22 @@ +import kotlin.reflect.jvm.internal.pcollections.HashPMap +import kotlin.test.* + +fun box(): String { + val map = HashPMap.empty()!! + + assertEquals(0, map.size()) + + assertFalse(map.containsKey("")) + assertFalse(map.containsKey("abacaba")) + assertEquals(null, map[""]) + assertEquals(null, map["lol"]) + + // Check that doesn't create a new map + assertEquals(map, map.minus("")) + + // Check that all empty()s are equal + val other = HashPMap.empty()!! + assertEquals(map, other) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/hashPMap/manyNumbers.kt b/compiler/testData/codegen/boxWithStdlib/hashPMap/manyNumbers.kt new file mode 100644 index 00000000000..408928f3331 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/hashPMap/manyNumbers.kt @@ -0,0 +1,47 @@ +import java.util.* +import kotlin.reflect.jvm.internal.pcollections.HashPMap +import kotlin.test.* + +fun digitSum(number: Int): Int { + var x = number + var ans = 0 + while (x != 0) { + ans += x % 10 + x /= 10 + } + return ans +} + +val N = 1000000 + +fun box(): String { + var map = HashPMap.empty()!! + + for (x in 1..N) { + map = map.plus(x, digitSum(x))!! + } + + assertEquals(N, map.size()) + + // Check in reverse order just in case + for (x in N downTo 1) { + assertTrue(map.containsKey(x), "Not found: $x") + assertEquals(digitSum(x), map[x], "Incorrect value for $x") + } + + // Delete in random order + val list = (1..N).toCollection(ArrayList()) + Collections.shuffle(list, Random(42)) + for (x in list) { + map = map.minus(x)!! + } + + assertEquals(0, map.size()) + + for (x in 1..N) { + assertFalse(map.containsKey(x), "Incorrectly found: $x") + assertEquals(null, map[x], "Incorrectly found value for $x") + } + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithDifferent.kt b/compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithDifferent.kt new file mode 100644 index 00000000000..7d06e9be51c --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithDifferent.kt @@ -0,0 +1,28 @@ +import kotlin.reflect.jvm.internal.pcollections.HashPMap +import kotlin.test.* + +fun box(): String { + var map = HashPMap.empty()!! + + map = map.plus("lol", 42)!! + map = map.plus("lol", 239)!! + + assertEquals(1, map.size()) + assertTrue(map.containsKey("lol")) + assertFalse(map.containsKey("")) + assertEquals(239, map["lol"]) + assertEquals(null, map[""]) + + map = map.plus("", 0)!! + map = map.plus("", 2.71828)!! + map = map.plus("lol", 42)!! + map = map.plus("", 3.14)!! + + assertEquals(2, map.size()) + assertTrue(map.containsKey("lol")) + assertTrue(map.containsKey("")) + assertEquals(42, map["lol"]) + assertEquals(3.14, map[""]) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithEqual.kt b/compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithEqual.kt new file mode 100644 index 00000000000..d94f22ff6f3 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithEqual.kt @@ -0,0 +1,28 @@ +import kotlin.reflect.jvm.internal.pcollections.HashPMap +import kotlin.test.* + +fun box(): String { + var map = HashPMap.empty()!! + + map = map.plus("lol", 42)!! + map = map.plus("lol", 42)!! + + assertEquals(1, map.size()) + assertTrue(map.containsKey("lol")) + assertFalse(map.containsKey("")) + assertEquals(42, map["lol"]) + assertEquals(null, map[""]) + + map = map.plus("", 0)!! + map = map.plus("", 0)!! + map = map.plus("lol", 42)!! + map = map.plus("", 0)!! + + assertEquals(2, map.size()) + assertTrue(map.containsKey("lol")) + assertTrue(map.containsKey("")) + assertEquals(42, map["lol"]) + assertEquals(0, map[""]) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusGet.kt b/compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusGet.kt new file mode 100644 index 00000000000..d9debf6fa77 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusGet.kt @@ -0,0 +1,24 @@ +import kotlin.reflect.jvm.internal.pcollections.HashPMap +import kotlin.test.* + +fun box(): String { + var map = HashPMap.empty()!! + + map = map.plus("lol", 42)!! + + assertEquals(1, map.size()) + assertTrue(map.containsKey("lol")) + assertFalse(map.containsKey("")) + assertEquals(42, map["lol"]) + assertEquals(null, map[""]) + + map = map.plus("", 0)!! + + assertEquals(2, map.size()) + assertTrue(map.containsKey("lol")) + assertTrue(map.containsKey("")) + assertEquals(42, map["lol"]) + assertEquals(0, map[""]) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusMinus.kt b/compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusMinus.kt new file mode 100644 index 00000000000..affdcff09ea --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusMinus.kt @@ -0,0 +1,23 @@ +import kotlin.reflect.jvm.internal.pcollections.HashPMap +import kotlin.test.* + +fun box(): String { + var map = HashPMap.empty()!! + + map = map.plus("lol", 42)!! + map = map.minus("lol")!! + + assertEquals(0, map.size()) + assertFalse(map.containsKey("lol")) + assertEquals(null, map["lol"]) + + map = map.plus("abc", "a")!! + map = map.minus("abc")!! + map = map.plus("abc", "d")!! + + assertEquals(1, map.size()) + assertTrue(map.containsKey("abc")) + assertEquals("d", map["abc"]) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index dc620d36cdf..2297e6821c8 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.codegen.generated.AbstractBlackBoxCodegenTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/boxWithStdlib") -@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Arrays.class, BlackBoxWithStdlibCodegenTestGenerated.CallableReference.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.Evaluate.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformNames.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Reflection.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class, BlackBoxWithStdlibCodegenTestGenerated.ToArray.class, BlackBoxWithStdlibCodegenTestGenerated.Vararg.class, BlackBoxWithStdlibCodegenTestGenerated.When.class}) +@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Arrays.class, BlackBoxWithStdlibCodegenTestGenerated.CallableReference.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.Evaluate.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.HashPMap.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformNames.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Reflection.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class, BlackBoxWithStdlibCodegenTestGenerated.ToArray.class, BlackBoxWithStdlibCodegenTestGenerated.Vararg.class, BlackBoxWithStdlibCodegenTestGenerated.When.class}) public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInBoxWithStdlib() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib"), Pattern.compile("^(.+)\\.kt$"), true); @@ -954,6 +954,44 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/hashPMap") + public static class HashPMap extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInHashPMap() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/hashPMap"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("empty.kt") + public void testEmpty() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/hashPMap/empty.kt"); + } + + @TestMetadata("manyNumbers.kt") + public void testManyNumbers() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/hashPMap/manyNumbers.kt"); + } + + @TestMetadata("rewriteWithDifferent.kt") + public void testRewriteWithDifferent() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithDifferent.kt"); + } + + @TestMetadata("rewriteWithEqual.kt") + public void testRewriteWithEqual() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/hashPMap/rewriteWithEqual.kt"); + } + + @TestMetadata("simplePlusGet.kt") + public void testSimplePlusGet() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusGet.kt"); + } + + @TestMetadata("simplePlusMinus.kt") + public void testSimplePlusMinus() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/hashPMap/simplePlusMinus.kt"); + } + + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/jdkAnnotations") public static class JdkAnnotations extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInJdkAnnotations() throws Exception { @@ -1704,6 +1742,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode suite.addTest(DataClasses.innerSuite()); suite.addTestSuite(Evaluate.class); suite.addTestSuite(FullJdk.class); + suite.addTestSuite(HashPMap.class); suite.addTestSuite(JdkAnnotations.class); suite.addTestSuite(PlatformNames.class); suite.addTest(Ranges.innerSuite()); From ef7fbe55cf53a8e626c30b914a329a7c2d00ce1a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 10 Jun 2014 22:14:25 +0400 Subject: [PATCH 22/38] Make KClass instances weak in foreignKClasses --- .../src/kotlin/reflect/jvm/internal/util.kt | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt index cf150b786b3..420555dafb1 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -16,8 +16,9 @@ package kotlin.reflect.jvm.internal +import java.lang.ref.WeakReference import java.lang.reflect.Method -import java.util.concurrent.ConcurrentHashMap +import java.util.Arrays import kotlin.reflect.jvm.internal.pcollections.HashPMap // TODO: use stdlib? @@ -47,15 +48,34 @@ private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: } -// TODO: should use weak references -private var foreignKClasses = HashPMap.empty, KClassImpl<*>>()!! +// TODO: collect nulls periodically +private var FOREIGN_K_CLASSES = HashPMap.empty>>>()!! fun foreignKotlinClass(jClass: Class): KClassImpl { - val cached = foreignKClasses[jClass] as? KClassImpl - if (cached != null) return cached - val result = KClassImpl(jClass) - foreignKClasses = foreignKClasses.plus(jClass, result)!! - return result + val name = jClass.getName() + val cached = FOREIGN_K_CLASSES[name] + if (cached != null) { + var i = cached.size - 1 + while (i >= 0) { + val kClass = cached[i].get() + if (kClass?.jClass == jClass) { + return kClass as KClassImpl + } + i-- + } + + val newArray = Arrays.copyOf(cached, cached.size + 1) as Array>> + val newKClass = KClassImpl(jClass) + newArray[cached.size] = WeakReference(newKClass) + FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray)!! + return newKClass + } + + val newKClass = KClassImpl(jClass) + val newArray = arrayOfNulls>>(1) + newArray[0] = WeakReference(newKClass) + FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray as Array>>)!! + return newKClass } private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject") From 0fa6b40731682bb35ccaf8097cfc6fd15b2ed172 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 24 Jun 2014 19:45:50 +0400 Subject: [PATCH 23/38] Make intermediate *Impl properties traits, not classes Otherwise multiple inheritance of classes would be needed to make implementations inherit correctly for mutable properties --- .../kotlin/reflect/jvm/internal/KCallableImpl.kt | 4 +--- .../reflect/jvm/internal/KExtensionPropertyImpl.kt | 10 +++++----- .../reflect/jvm/internal/KMemberPropertyImpl.kt | 6 +++--- .../kotlin/reflect/jvm/internal/KPropertyImpl.kt | 13 +++++++------ .../reflect/jvm/internal/KTopLevelPropertyImpl.kt | 10 +++++----- .../kotlin/reflect/jvm/internal/KVariableImpl.kt | 9 ++------- 6 files changed, 23 insertions(+), 29 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt index cd3b87eabe9..0164fcbc513 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -16,6 +16,4 @@ package kotlin.reflect.jvm.internal -abstract class KCallableImpl( - public override val name: String -) : KCallable +trait KCallableImpl : KCallable diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt index 0850703dad6..c39464c9b32 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt @@ -19,12 +19,12 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.Method open class KExtensionPropertyImpl( - name: String, + public override val name: String, protected val owner: KPackageImpl, protected val receiverClass: Class -) : KExtensionProperty, KPropertyImpl(name) { +) : KExtensionProperty, KPropertyImpl { // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields - protected val getter: Method = owner.jClass.getMethod(getterName(name), receiverClass) + val getter: Method = owner.jClass.getMethod(getterName(name), receiverClass) override fun get(receiver: T): R { return getter(null, receiver) as R @@ -35,8 +35,8 @@ class KMutableExtensionPropertyImpl( name: String, owner: KPackageImpl, receiverClass: Class -) : KMutableExtensionProperty, KExtensionPropertyImpl(name, owner, receiverClass) { - private val setter = owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!) +) : KMutableExtensionProperty, KMutablePropertyImpl, KExtensionPropertyImpl(name, owner, receiverClass) { + val setter = owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!) override fun set(receiver: T, value: R) { setter.invoke(null, receiver, value) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 86ad94691aa..f44573619fd 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -20,9 +20,9 @@ import java.lang.reflect.Field import java.lang.reflect.Method open class KMemberPropertyImpl( - name: String, + public override val name: String, protected val owner: KClassImpl -) : KMemberProperty, KPropertyImpl(name) { +) : KMemberProperty, KPropertyImpl { val field: Field? = if (owner.origin == KClassOrigin.FOREIGN) { owner.jClass.getField(name) @@ -48,7 +48,7 @@ open class KMemberPropertyImpl( class KMutableMemberPropertyImpl( name: String, owner: KClassImpl -) : KMutableMemberProperty, KMemberPropertyImpl(name, owner) { +) : KMutableMemberProperty, KMutablePropertyImpl, KMemberPropertyImpl(name, owner) { val setter: Method? = if (owner.origin == KClassOrigin.KOTLIN) { owner.jClass.getMaybeDeclaredMethod(setterName(name), getter!!.getReturnType()!!) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt index 8dbf08339a5..f4cbba5ff10 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -16,11 +16,12 @@ package kotlin.reflect.jvm.internal -abstract class KPropertyImpl( - name: String -) : KProperty, KCallableImpl(name) +import java.lang.reflect.* + +trait KPropertyImpl : KProperty, KCallableImpl { + +} -abstract class KMutablePropertyImpl( - name: String -) : KMutableProperty, KPropertyImpl(name) +trait KMutablePropertyImpl : KMutableProperty, KPropertyImpl { +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt index b386d0c1a6a..6ae1177d3ed 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt @@ -19,11 +19,11 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.Method open class KTopLevelPropertyImpl( - name: String, + public override val name: String, protected val owner: KPackageImpl -) : KTopLevelProperty, KVariableImpl(name) { +) : KTopLevelProperty, KVariableImpl { // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields - protected val getter: Method = owner.jClass.getMethod(getterName(name)) + val getter: Method = owner.jClass.getMethod(getterName(name)) override fun get(): R { return getter(null) as R @@ -33,8 +33,8 @@ open class KTopLevelPropertyImpl( class KMutableTopLevelPropertyImpl( name: String, owner: KPackageImpl -) : KMutableTopLevelProperty, KTopLevelPropertyImpl(name, owner) { - private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) +) : KMutableTopLevelProperty, KMutableVariableImpl, KTopLevelPropertyImpl(name, owner) { + val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) override fun set(value: R) { setter.invoke(null, value) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt index 9932b7559a5..5fac1d5141a 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt @@ -16,11 +16,6 @@ package kotlin.reflect.jvm.internal -abstract class KVariableImpl( - name: String -) : KVariable, KPropertyImpl(name) +trait KVariableImpl : KVariable, KPropertyImpl - -abstract class KMutableVariableImpl( - name: String -) : KMutableVariable, KVariableImpl(name) +trait KMutableVariableImpl : KMutableVariable, KVariableImpl, KMutablePropertyImpl From e60428b5401fb29cea8bf5667f6ff1b7834764d6 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 24 Jun 2014 21:40:23 +0400 Subject: [PATCH 24/38] Improve performance of foreignKClasses, add comments --- .../reflect/jvm/internal/foreignKClasses.kt | 65 +++++++++++++++++++ .../src/kotlin/reflect/jvm/internal/util.kt | 33 ---------- 2 files changed, 65 insertions(+), 33 deletions(-) create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt new file mode 100644 index 00000000000..d13dd573029 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +import java.lang.ref.WeakReference +import kotlin.reflect.jvm.internal.pcollections.HashPMap + +// TODO: collect nulls periodically +// Key of the map is Class.getName(), each value is either a WeakReference> or an Array>>. +// Arrays are needed because the same class can be loaded by different class loaders, which results in different Class instances. +// This variable is not volatile intentionally: we don't care if there's a data race on it and some KClass instances will be lost. +// We do care however about general performance on read access to it, thus no synchronization is done here whatsoever +private var FOREIGN_K_CLASSES = HashPMap.empty()!! + +// This function is invoked on each reflection access to Java classes, properties, etc. Performance is critical here. +fun foreignKotlinClass(jClass: Class): KClassImpl { + val name = jClass.getName() + val cached = FOREIGN_K_CLASSES[name] + if (cached is WeakReference<*>) { + val kClass = cached.get() as KClassImpl? + if (kClass?.jClass == jClass) { + return kClass!! + } + } + else if (cached != null) { + // If the cached value is not a weak reference, it's an array of weak references + cached as Array>> + for (ref in cached) { + val kClass = ref.get() + if (kClass?.jClass == jClass) { + return kClass!! + } + } + + // This is the most unlikely case: we found a cached array of references of length at least 2 (can't be 1 because + // the single element would be cached instead), and none of those classes is the one we're looking for + val size = cached.size + // Don't use Array constructor because it creates a lambda + val newArray = arrayOfNulls>>(size + 1) + // Don't use Arrays.copyOf because it works reflectively + System.arraycopy(cached, 0, newArray, 0, size) + val newKClass = KClassImpl(jClass) + newArray[size] = WeakReference(newKClass) + FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray)!! + return newKClass + } + + val newKClass = KClassImpl(jClass) + FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, WeakReference(newKClass))!! + return newKClass +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt index 420555dafb1..1ea227e338a 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -16,10 +16,7 @@ package kotlin.reflect.jvm.internal -import java.lang.ref.WeakReference import java.lang.reflect.Method -import java.util.Arrays -import kotlin.reflect.jvm.internal.pcollections.HashPMap // TODO: use stdlib? suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") @@ -48,36 +45,6 @@ private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: } -// TODO: collect nulls periodically -private var FOREIGN_K_CLASSES = HashPMap.empty>>>()!! - -fun foreignKotlinClass(jClass: Class): KClassImpl { - val name = jClass.getName() - val cached = FOREIGN_K_CLASSES[name] - if (cached != null) { - var i = cached.size - 1 - while (i >= 0) { - val kClass = cached[i].get() - if (kClass?.jClass == jClass) { - return kClass as KClassImpl - } - i-- - } - - val newArray = Arrays.copyOf(cached, cached.size + 1) as Array>> - val newKClass = KClassImpl(jClass) - newArray[cached.size] = WeakReference(newKClass) - FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray)!! - return newKClass - } - - val newKClass = KClassImpl(jClass) - val newArray = arrayOfNulls>>(1) - newArray[0] = WeakReference(newKClass) - FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray as Array>>)!! - return newKClass -} - private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject") fun kotlinClass(jClass: Class): KClassImpl { From 7cbbeb257e2894f9f70af93cc302d3c302465b98 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 1 Jul 2014 16:32:06 +0400 Subject: [PATCH 25/38] Add NotNull annotations to HashPMap --- .../src/kotlin/reflect/jvm/internal/foreignKClasses.kt | 6 +++--- .../kotlin/reflect/jvm/internal/pcollections/HashPMap.java | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt index d13dd573029..adf795c49ce 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt @@ -24,7 +24,7 @@ import kotlin.reflect.jvm.internal.pcollections.HashPMap // Arrays are needed because the same class can be loaded by different class loaders, which results in different Class instances. // This variable is not volatile intentionally: we don't care if there's a data race on it and some KClass instances will be lost. // We do care however about general performance on read access to it, thus no synchronization is done here whatsoever -private var FOREIGN_K_CLASSES = HashPMap.empty()!! +private var FOREIGN_K_CLASSES = HashPMap.empty() // This function is invoked on each reflection access to Java classes, properties, etc. Performance is critical here. fun foreignKotlinClass(jClass: Class): KClassImpl { @@ -55,11 +55,11 @@ fun foreignKotlinClass(jClass: Class): KClassImpl { System.arraycopy(cached, 0, newArray, 0, size) val newKClass = KClassImpl(jClass) newArray[size] = WeakReference(newKClass) - FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray)!! + FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray) return newKClass } val newKClass = KClassImpl(jClass) - FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, WeakReference(newKClass))!! + FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, WeakReference(newKClass)) return newKClass } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java index 6909aa304c6..473b2d6d922 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashPMap.java @@ -16,6 +16,8 @@ package kotlin.reflect.jvm.internal.pcollections; +import org.jetbrains.annotations.NotNull; + /** * A persistent map from non-null keys to non-null values. */ @@ -23,6 +25,7 @@ public final class HashPMap { private static final HashPMap EMPTY = new HashPMap(IntTreePMap.>>empty(), 0); @SuppressWarnings("unchecked") + @NotNull public static HashPMap empty() { return (HashPMap) HashPMap.EMPTY; } @@ -51,6 +54,7 @@ public final class HashPMap { return null; } + @NotNull public HashPMap plus(K key, V value) { ConsPStack> entries = getEntries(key.hashCode()); int size0 = entries.size(); @@ -60,6 +64,7 @@ public final class HashPMap { return new HashPMap(intMap.plus(key.hashCode(), entries), size - size0 + entries.size()); } + @NotNull public HashPMap minus(Object key) { ConsPStack> entries = getEntries(key.hashCode()); int i = keyIndexIn(entries, key); From 8b619eceedd5e4b7b4a33f234cf6c5e5fe12d668 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 24 Jun 2014 21:59:14 +0400 Subject: [PATCH 26/38] Make KMemberProperty's T parameter have a non-null bound --- core/reflection/src/kotlin/reflect/KMemberProperty.kt | 4 ++-- .../src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/reflection/src/kotlin/reflect/KMemberProperty.kt b/core/reflection/src/kotlin/reflect/KMemberProperty.kt index 233a369617f..2c7f46d2e05 100644 --- a/core/reflection/src/kotlin/reflect/KMemberProperty.kt +++ b/core/reflection/src/kotlin/reflect/KMemberProperty.kt @@ -16,10 +16,10 @@ package kotlin.reflect -public trait KMemberProperty : KProperty { +public trait KMemberProperty : KProperty { public fun get(receiver: T): R } -public trait KMutableMemberProperty : KMemberProperty, KMutableProperty { +public trait KMutableMemberProperty : KMemberProperty, KMutableProperty { public fun set(receiver: T, value: R) } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index f44573619fd..0f3d18d96e9 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -19,7 +19,7 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.Field import java.lang.reflect.Method -open class KMemberPropertyImpl( +open class KMemberPropertyImpl( public override val name: String, protected val owner: KClassImpl ) : KMemberProperty, KPropertyImpl { @@ -45,7 +45,7 @@ open class KMemberPropertyImpl( } } -class KMutableMemberPropertyImpl( +class KMutableMemberPropertyImpl( name: String, owner: KClassImpl ) : KMutableMemberProperty, KMutablePropertyImpl, KMemberPropertyImpl(name, owner) { From 1ad037f62179d5b295c270c1f3aa947a8112e483 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 25 Jun 2014 04:02:03 +0400 Subject: [PATCH 27/38] Fix KClassOrigin for non-Kotlin classes Check against presence of KotlinClass annotation --- .../org/jetbrains/jet/compiler/android/SpecialFiles.java | 1 + compiler/testData/codegen/boxWithJava/.empty | 0 .../referenceToJavaFieldOfKotlinSubclass/J.java | 3 +++ .../boxWithJava/referenceToJavaFieldOfKotlinSubclass/K.kt | 7 +++++++ .../generated/BlackBoxWithJavaCodegenTestGenerated.java | 5 +++++ .../src/kotlin/reflect/jvm/internal/KClassImpl.kt | 4 +++- 6 files changed, 19 insertions(+), 1 deletion(-) delete mode 100644 compiler/testData/codegen/boxWithJava/.empty create mode 100644 compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/J.java create mode 100644 compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/K.kt diff --git a/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java index 4056960242a..d162776ed5a 100644 --- a/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java +++ b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java @@ -57,6 +57,7 @@ public class SpecialFiles { private static void fillExcludedFiles() { excludedFiles.add("boxAgainstJava"); // Must compile Java files before + excludedFiles.add("boxWithJava"); // Must compile Java files before excludedFiles.add("boxMultiFile"); // MultiFileTest not supported yet excludedFiles.add("boxInline"); // MultiFileTest not supported yet diff --git a/compiler/testData/codegen/boxWithJava/.empty b/compiler/testData/codegen/boxWithJava/.empty deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/J.java b/compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/J.java new file mode 100644 index 00000000000..9e92f8601ef --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/J.java @@ -0,0 +1,3 @@ +public class J extends K { + public final int value = 42; +} diff --git a/compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/K.kt b/compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/K.kt new file mode 100644 index 00000000000..79a425eb69b --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/K.kt @@ -0,0 +1,7 @@ +open class K + +fun box(): String { + val f = J::value + val a = J() + return if (f.get(a) == 42) "OK" else "Fail: ${f[a]}" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 612db880d58..525144c9800 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -36,4 +36,9 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithJava"), Pattern.compile("^([^\\.]+)$"), false); } + @TestMetadata("referenceToJavaFieldOfKotlinSubclass") + public void testReferenceToJavaFieldOfKotlinSubclass() throws Exception { + doTestWithJava("compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/"); + } + } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index e191d9878b6..cb8d2f337b4 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -16,6 +16,8 @@ package kotlin.reflect.jvm.internal +import kotlin.reflect.jvm.KOTLIN_CLASS_ANNOTATION_CLASS + enum class KClassOrigin { BUILT_IN KOTLIN @@ -26,7 +28,7 @@ class KClassImpl( val jClass: Class ) : KClass { val origin: KClassOrigin = - if (K_OBJECT_CLASS.isAssignableFrom(jClass)) { + if (K_OBJECT_CLASS.isAssignableFrom(jClass) && jClass.isAnnotationPresent(KOTLIN_CLASS_ANNOTATION_CLASS)) { KClassOrigin.KOTLIN } else { From 9c5596cddb4c6b5b8e1657258339c9ce322799a5 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 25 Jun 2014 18:26:27 +0400 Subject: [PATCH 28/38] Expose Java reflection objects out of Kotlin ones --- .../reflect/jvm/internal/KExtensionPropertyImpl.kt | 8 +++++--- .../kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt | 9 ++++----- .../src/kotlin/reflect/jvm/internal/KPropertyImpl.kt | 3 +++ .../kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt | 9 ++++++--- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt index c39464c9b32..50406e2c72e 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt @@ -16,15 +16,17 @@ package kotlin.reflect.jvm.internal -import java.lang.reflect.Method +import java.lang.reflect.* open class KExtensionPropertyImpl( public override val name: String, protected val owner: KPackageImpl, protected val receiverClass: Class ) : KExtensionProperty, KPropertyImpl { + override val field: Field? get() = null + // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields - val getter: Method = owner.jClass.getMethod(getterName(name), receiverClass) + override val getter: Method = owner.jClass.getMethod(getterName(name), receiverClass) override fun get(receiver: T): R { return getter(null, receiver) as R @@ -36,7 +38,7 @@ class KMutableExtensionPropertyImpl( owner: KPackageImpl, receiverClass: Class ) : KMutableExtensionProperty, KMutablePropertyImpl, KExtensionPropertyImpl(name, owner, receiverClass) { - val setter = owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!) + override val setter: Method = owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!) override fun set(receiver: T, value: R) { setter.invoke(null, receiver, value) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 0f3d18d96e9..6df4129886a 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -16,21 +16,20 @@ package kotlin.reflect.jvm.internal -import java.lang.reflect.Field -import java.lang.reflect.Method +import java.lang.reflect.* open class KMemberPropertyImpl( public override val name: String, protected val owner: KClassImpl ) : KMemberProperty, KPropertyImpl { - val field: Field? = + override val field: Field? = if (owner.origin == KClassOrigin.FOREIGN) { owner.jClass.getField(name) } else null // TODO: extract, make lazy (weak?), use our descriptors knowledge - val getter: Method? = + override val getter: Method? = if (owner.origin == KClassOrigin.KOTLIN) { owner.jClass.getMaybeDeclaredMethod(getterName(name)) } @@ -49,7 +48,7 @@ class KMutableMemberPropertyImpl( name: String, owner: KClassImpl ) : KMutableMemberProperty, KMutablePropertyImpl, KMemberPropertyImpl(name, owner) { - val setter: Method? = + override val setter: Method? = if (owner.origin == KClassOrigin.KOTLIN) { owner.jClass.getMaybeDeclaredMethod(setterName(name), getter!!.getReturnType()!!) } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt index f4cbba5ff10..335a159eeb5 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -19,9 +19,12 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* trait KPropertyImpl : KProperty, KCallableImpl { + val field: Field? + val getter: Method? } trait KMutablePropertyImpl : KMutableProperty, KPropertyImpl { + val setter: Method? } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt index 6ae1177d3ed..a95bed1131f 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt @@ -16,14 +16,17 @@ package kotlin.reflect.jvm.internal -import java.lang.reflect.Method +import java.lang.reflect.* open class KTopLevelPropertyImpl( public override val name: String, protected val owner: KPackageImpl ) : KTopLevelProperty, KVariableImpl { + // TODO: load the field from the corresponding package part + override val field: Field? get() = null + // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields - val getter: Method = owner.jClass.getMethod(getterName(name)) + override val getter: Method = owner.jClass.getMethod(getterName(name)) override fun get(): R { return getter(null) as R @@ -34,7 +37,7 @@ class KMutableTopLevelPropertyImpl( name: String, owner: KPackageImpl ) : KMutableTopLevelProperty, KMutableVariableImpl, KTopLevelPropertyImpl(name, owner) { - val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) + override val setter: Method = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) override fun set(value: R) { setter.invoke(null, value) From f73b8b9ff842a3fdf77ecc32b4a7aee45f132f7d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 25 Jun 2014 17:37:48 +0400 Subject: [PATCH 29/38] Extract KForeignMemberProperty out of KMemberPropertyImpl KClassImpl is now able to create a property by the name, according to its origin --- .../jet/codegen/ExpressionCodegen.java | 111 ++++++++++-------- .../lang/resolve/java/AsmTypeConstants.java | 5 +- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 29 ++++- .../jvm/internal/KForeignMemberProperty.kt | 43 +++++++ .../jvm/internal/KMemberPropertyImpl.kt | 38 ++---- .../kotlin/reflect/jvm/internal/factory.kt | 7 -- .../src/kotlin/reflect/jvm/internal/util.kt | 12 -- .../src/kotlin/reflect/jvm/properties.kt | 24 ++-- 8 files changed, 151 insertions(+), 118 deletions(-) create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 92a0a2c1856..1b04b121b57 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -70,7 +70,6 @@ import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.*; import static org.jetbrains.jet.codegen.AsmUtil.*; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; import static org.jetbrains.jet.codegen.JvmCodegenUtil.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; @@ -78,6 +77,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.isVarCapturedInClosure; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; import static org.jetbrains.org.objectweb.asm.Opcodes.*; @@ -2427,70 +2427,77 @@ public class ExpressionCodegen extends JetVisitor implem if (variableDescriptor != null) { VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor(); - ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); - - String reflectionFieldOwner; - Type ownerType; - String reflectionFieldName; - Method factory; - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); if (containingDeclaration instanceof PackageFragmentDescriptor) { - reflectionFieldOwner = - PackageClassUtils.getPackageClassInternalName(((PackageFragmentDescriptor) containingDeclaration).getFqName()); - - ownerType = K_PACKAGE_IMPL_TYPE; - reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME; - - if (receiverParameter != null) { - factory = descriptor.isVar() - ? method("mutableExtensionProperty", K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType, - getType(Class.class)) - : method("extensionProperty", K_EXTENSION_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType, - getType(Class.class)); - } - else { - factory = descriptor.isVar() - ? method("mutableTopLevelProperty", K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType) - : method("topLevelProperty", K_TOP_LEVEL_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType); - } + return generateTopLevelPropertyReference(descriptor); } else if (containingDeclaration instanceof ClassDescriptor) { - reflectionFieldOwner = typeMapper.mapClass((ClassDescriptor) containingDeclaration).getInternalName(); - ownerType = K_CLASS_IMPL_TYPE; - reflectionFieldName = JvmAbi.KOTLIN_CLASS_FIELD_NAME; - - factory = descriptor.isVar() - ? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType) - : method("memberProperty", K_MEMBER_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType); + return generateMemberPropertyReference(descriptor); } else { throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration); } - - v.visitLdcInsn(descriptor.getName().asString()); - - if (containingDeclaration instanceof JavaClassDescriptor) { - v.aconst(Type.getObjectType(reflectionFieldOwner)); - v.invokestatic(REFLECTION_INTERNAL_PACKAGE, "foreignKotlinClass", - Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false); - } - else { - // TODO: built-in classes - v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor()); - } - - if (receiverParameter != null) { - putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter)); - } - - v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factory.getName(), factory.getDescriptor(), false); - return StackValue.onStack(factory.getReturnType()); } throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); } + @NotNull + private StackValue generateTopLevelPropertyReference(@NotNull VariableDescriptor descriptor) { + PackageFragmentDescriptor containingPackage = (PackageFragmentDescriptor) descriptor.getContainingDeclaration(); + String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(containingPackage.getFqName()); + + ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); + Method factoryMethod; + if (receiverParameter != null) { + Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE, getType(Class.class)}; + factoryMethod = descriptor.isVar() + ? method("mutableExtensionProperty", K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes) + : method("extensionProperty", K_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes); + } + else { + Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE}; + factoryMethod = descriptor.isVar() + ? method("mutableTopLevelProperty", K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE, parameterTypes) + : method("topLevelProperty", K_TOP_LEVEL_PROPERTY_IMPL_TYPE, parameterTypes); + } + + v.visitLdcInsn(descriptor.getName().asString()); + v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_IMPL_TYPE.getDescriptor()); + + if (receiverParameter != null) { + putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter)); + } + + v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factoryMethod.getName(), factoryMethod.getDescriptor(), false); + + return StackValue.onStack(factoryMethod.getReturnType()); + } + + @NotNull + private StackValue generateMemberPropertyReference(@NotNull VariableDescriptor descriptor) { + ClassDescriptor containingClass = (ClassDescriptor) descriptor.getContainingDeclaration(); + Type classAsmType = typeMapper.mapClass(containingClass); + + if (containingClass instanceof JavaClassDescriptor) { + v.aconst(classAsmType); + v.invokestatic(REFLECTION_INTERNAL_PACKAGE, "foreignKotlinClass", + Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false); + } + else { + v.getstatic(classAsmType.getInternalName(), JvmAbi.KOTLIN_CLASS_FIELD_NAME, K_CLASS_IMPL_TYPE.getDescriptor()); + } + + Method factoryMethod = descriptor.isVar() + ? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE) + : method("memberProperty", K_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE); + + v.visitLdcInsn(descriptor.getName().asString()); + v.invokevirtual(K_CLASS_IMPL_TYPE.getInternalName(), factoryMethod.getName(), factoryMethod.getDescriptor(), false); + + return StackValue.onStack(factoryMethod.getReturnType()); + } + private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased { private final ResolvedCall resolvedCall; private final FunctionDescriptor referencedFunction; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index e1099d1dbc6..c4d094cb347 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -38,12 +38,13 @@ public class AsmTypeConstants { public static final Type PROPERTY_METADATA_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadata"); public static final Type PROPERTY_METADATA_IMPL_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadataImpl"); + public static final Type K_MEMBER_PROPERTY_TYPE = Type.getObjectType("kotlin/reflect/KMemberProperty"); + public static final Type K_MUTABLE_MEMBER_PROPERTY_TYPE = Type.getObjectType("kotlin/reflect/KMutableMemberProperty"); + public static final Type K_CLASS_IMPL_TYPE = reflectInternal("KClassImpl"); public static final Type K_PACKAGE_IMPL_TYPE = reflectInternal("KPackageImpl"); public static final Type K_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KTopLevelPropertyImpl"); public static final Type K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelPropertyImpl"); - public static final Type K_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMemberPropertyImpl"); - public static final Type K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMutableMemberPropertyImpl"); public static final Type K_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KExtensionPropertyImpl"); public static final Type K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KMutableExtensionPropertyImpl"); diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index cb8d2f337b4..ca2f4efba63 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -16,23 +16,40 @@ package kotlin.reflect.jvm.internal -import kotlin.reflect.jvm.KOTLIN_CLASS_ANNOTATION_CLASS - enum class KClassOrigin { BUILT_IN KOTLIN FOREIGN } -class KClassImpl( - val jClass: Class -) : KClass { +private val KOTLIN_CLASS_ANNOTATION_CLASS = Class.forName("kotlin.jvm.internal.KotlinClass") as Class +private val KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS = Class.forName("kotlin.jvm.internal.KotlinSyntheticClass") as Class + +class KClassImpl(val jClass: Class) : KClass { + // TODO: write metadata to local classes val origin: KClassOrigin = - if (K_OBJECT_CLASS.isAssignableFrom(jClass) && jClass.isAnnotationPresent(KOTLIN_CLASS_ANNOTATION_CLASS)) { + if (jClass.isAnnotationPresent(KOTLIN_CLASS_ANNOTATION_CLASS) || + jClass.isAnnotationPresent(KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS)) { KClassOrigin.KOTLIN } else { KClassOrigin.FOREIGN // TODO: built-in classes } + + fun memberProperty(name: String): KMemberProperty = + if (origin identityEquals KClassOrigin.KOTLIN) { + KMemberPropertyImpl(name, this) + } + else { + KForeignMemberProperty(name, this) + } + + fun mutableMemberProperty(name: String): KMutableMemberProperty = + if (origin identityEquals KClassOrigin.KOTLIN) { + KMutableMemberPropertyImpl(name, this) + } + else { + KMutableForeignMemberProperty(name, this) + } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt new file mode 100644 index 00000000000..97ef4430acf --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +import java.lang.reflect.* + +open class KForeignMemberProperty( + public override val name: String, + protected val owner: KClassImpl +) : KMemberProperty, KPropertyImpl { + override val field: Field = owner.jClass.getField(name) + + override val getter: Method? get() = null + + override fun get(receiver: T): R { + return field.get(receiver) as R + } +} + +class KMutableForeignMemberProperty( + name: String, + owner: KClassImpl +) : KMutableMemberProperty, KMutablePropertyImpl, KForeignMemberProperty(name, owner) { + override val setter: Method? get() = null + + override fun set(receiver: T, value: R) { + field.set(receiver, value) + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 6df4129886a..d237f450004 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -18,29 +18,25 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* +// TODO: properties of built-in classes + open class KMemberPropertyImpl( public override val name: String, protected val owner: KClassImpl ) : KMemberProperty, KPropertyImpl { - override val field: Field? = - if (owner.origin == KClassOrigin.FOREIGN) { - owner.jClass.getField(name) - } - else null + override val field: Field? + get() = try { + owner.jClass.getDeclaredField(name) + } + catch (e: NoSuchFieldException) { + null + } // TODO: extract, make lazy (weak?), use our descriptors knowledge - override val getter: Method? = - if (owner.origin == KClassOrigin.KOTLIN) { - owner.jClass.getMaybeDeclaredMethod(getterName(name)) - } - else null + override val getter: Method = owner.jClass.getMaybeDeclaredMethod(getterName(name)) - // TODO: built-in classes override fun get(receiver: T): R { - if (getter != null) { - return getter!!(receiver) as R - } - return field!!.get(receiver) as R + return getter(receiver) as R } } @@ -48,17 +44,9 @@ class KMutableMemberPropertyImpl( name: String, owner: KClassImpl ) : KMutableMemberProperty, KMutablePropertyImpl, KMemberPropertyImpl(name, owner) { - override val setter: Method? = - if (owner.origin == KClassOrigin.KOTLIN) { - owner.jClass.getMaybeDeclaredMethod(setterName(name), getter!!.getReturnType()!!) - } - else null + override val setter: Method = owner.jClass.getMaybeDeclaredMethod(setterName(name), getter.getReturnType()!!) override fun set(receiver: T, value: R) { - if (setter != null) { - setter!!(receiver, value) - return - } - field!!.set(receiver, value) + setter(receiver, value) } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt index 1979953a35c..9ec07585bef 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt @@ -34,10 +34,3 @@ fun extensionProperty(name: String, owner: KPackageImpl, receiver: Class) fun mutableExtensionProperty(name: String, owner: KPackageImpl, receiver: Class): KMutableExtensionPropertyImpl = KMutableExtensionPropertyImpl(name, owner, receiver) - -fun memberProperty(name: String, owner: KClassImpl): KMemberPropertyImpl = - KMemberPropertyImpl(name, owner) - -fun mutableMemberProperty(name: String, owner: KClassImpl): KMutableMemberPropertyImpl = - KMutableMemberPropertyImpl(name, owner) - diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt index 1ea227e338a..84d6b0a3120 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -43,15 +43,3 @@ private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: return getDeclaredMethod(name, *parameterTypes) } } - - -private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject") - -fun kotlinClass(jClass: Class): KClassImpl { - if (K_OBJECT_CLASS.isAssignableFrom(jClass)) { - val field = jClass.getDeclaredField("\$kotlinClass") - return field.get(null) as KClassImpl - } - // TODO: built-in classes - return foreignKotlinClass(jClass) -} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt index e7e4abdd452..1c7825f0489 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt @@ -16,19 +16,14 @@ package kotlin.reflect.jvm -import kotlin.reflect.jvm.internal.KMemberPropertyImpl -import kotlin.reflect.jvm.internal.KMutableMemberPropertyImpl +import kotlin.reflect.jvm.internal.* public var KProperty.accessible: Boolean get() { return when (this) { - is KMutableMemberPropertyImpl<*, R> -> - field?.isAccessible() ?: true && - getter?.isAccessible() ?: true && - setter?.isAccessible() ?: true - is KMemberPropertyImpl<*, R> -> - field?.isAccessible() ?: true && - getter?.isAccessible() ?: true + is KMutableMemberPropertyImpl<*, R> -> getter.isAccessible() && setter.isAccessible() + is KMemberPropertyImpl<*, R> -> getter.isAccessible() + is KForeignMemberProperty<*, R> -> field.isAccessible() else -> { // Non-member properties always have public visibility on JVM, thus accessible has no effect on them true @@ -38,13 +33,14 @@ public var KProperty.accessible: Boolean set(value) { when (this) { is KMutableMemberPropertyImpl<*, R> -> { - field?.setAccessible(value) - getter?.setAccessible(value) - setter?.setAccessible(value) + getter.setAccessible(value) + setter.setAccessible(value) } is KMemberPropertyImpl<*, R> -> { - field?.setAccessible(value) - getter?.setAccessible(value) + getter.setAccessible(value) + } + is KForeignMemberProperty<*, R> -> { + field.setAccessible(value) } } } From d32a02f21abc6ff1a5bdb65a3bfd82e713ce97ab Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 1 Jul 2014 17:12:47 +0400 Subject: [PATCH 30/38] Modify top-level/extension property hierarchy - rename KTopLevelProperty to KTopLevelVariable - create KTopLevelExtensionProperty, a subclass of KExtensionProperty - create KTopLevelProperty, a superclass of KTopLevelVariable and KTopLevelExtensionProperty. (In the future, it will have a container of type KPackage.) --- .../jet/codegen/ExpressionCodegen.java | 8 +++---- .../lang/resolve/java/AsmTypeConstants.java | 8 +++---- .../jet/lang/reflect/ReflectionTypes.kt | 16 +++++++------- .../property/extensionFromTopLevel.kt | 3 +++ .../property/topLevelFromTopLevel.kt | 5 ++++- .../reflect/KTopLevelExtensionProperty.kt | 21 +++++++++++++++++++ .../src/kotlin/reflect/KTopLevelProperty.kt | 4 ++-- .../src/kotlin/reflect/KTopLevelVariable.kt | 21 +++++++++++++++++++ ...l.kt => KTopLevelExtensionPropertyImpl.kt} | 8 +++---- ...opertyImpl.kt => KTopLevelVariableImpl.kt} | 8 +++---- .../kotlin/reflect/jvm/internal/factory.kt | 16 +++++++------- 11 files changed, 83 insertions(+), 35 deletions(-) create mode 100644 core/reflection/src/kotlin/reflect/KTopLevelExtensionProperty.kt create mode 100644 core/reflection/src/kotlin/reflect/KTopLevelVariable.kt rename core/runtime.jvm/src/kotlin/reflect/jvm/internal/{KExtensionPropertyImpl.kt => KTopLevelExtensionPropertyImpl.kt} (82%) rename core/runtime.jvm/src/kotlin/reflect/jvm/internal/{KTopLevelPropertyImpl.kt => KTopLevelVariableImpl.kt} (85%) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 1b04b121b57..af203a1a0a0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2452,14 +2452,14 @@ public class ExpressionCodegen extends JetVisitor implem if (receiverParameter != null) { Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE, getType(Class.class)}; factoryMethod = descriptor.isVar() - ? method("mutableExtensionProperty", K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes) - : method("extensionProperty", K_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes); + ? method("mutableTopLevelExtensionProperty", K_MUTABLE_TOP_LEVEL_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes) + : method("topLevelExtensionProperty", K_TOP_LEVEL_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes); } else { Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE}; factoryMethod = descriptor.isVar() - ? method("mutableTopLevelProperty", K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE, parameterTypes) - : method("topLevelProperty", K_TOP_LEVEL_PROPERTY_IMPL_TYPE, parameterTypes); + ? method("mutableTopLevelVariable", K_MUTABLE_TOP_LEVEL_VARIABLE_IMPL_TYPE, parameterTypes) + : method("topLevelVariable", K_TOP_LEVEL_VARIABLE_IMPL_TYPE, parameterTypes); } v.visitLdcInsn(descriptor.getName().asString()); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index c4d094cb347..0f65adb0d8b 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -43,10 +43,10 @@ public class AsmTypeConstants { public static final Type K_CLASS_IMPL_TYPE = reflectInternal("KClassImpl"); public static final Type K_PACKAGE_IMPL_TYPE = reflectInternal("KPackageImpl"); - public static final Type K_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KTopLevelPropertyImpl"); - public static final Type K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelPropertyImpl"); - public static final Type K_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KExtensionPropertyImpl"); - public static final Type K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KMutableExtensionPropertyImpl"); + public static final Type K_TOP_LEVEL_VARIABLE_IMPL_TYPE = reflectInternal("KTopLevelVariableImpl"); + public static final Type K_MUTABLE_TOP_LEVEL_VARIABLE_IMPL_TYPE = reflectInternal("KMutableTopLevelVariableImpl"); + public static final Type K_TOP_LEVEL_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KTopLevelExtensionPropertyImpl"); + public static final Type K_MUTABLE_TOP_LEVEL_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelExtensionPropertyImpl"); public static final String REFLECTION_INTERNAL_PACKAGE = reflectInternal("InternalPackage").getInternalName(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt b/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt index 299d3b2c8fa..a1e53d6b063 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt @@ -49,12 +49,12 @@ 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 kTopLevelProperty: ClassDescriptor by ClassLookup - public val kMutableTopLevelProperty: ClassDescriptor by ClassLookup + public val kTopLevelVariable: ClassDescriptor by ClassLookup + public val kMutableTopLevelVariable: ClassDescriptor by ClassLookup public val kMemberProperty: ClassDescriptor by ClassLookup public val kMutableMemberProperty: ClassDescriptor by ClassLookup - public val kExtensionProperty: ClassDescriptor by ClassLookup - public val kMutableExtensionProperty: ClassDescriptor by ClassLookup + public val kTopLevelExtensionProperty: ClassDescriptor by ClassLookup + public val kMutableTopLevelExtensionProperty: ClassDescriptor by ClassLookup public fun getKFunctionType( annotations: Annotations, @@ -85,14 +85,14 @@ public class ReflectionTypes(private val module: ModuleDescriptor) { mutable: Boolean ): JetType { val classDescriptor = if (mutable) when { - extensionProperty -> kMutableExtensionProperty + extensionProperty -> kMutableTopLevelExtensionProperty receiverType != null -> kMutableMemberProperty - else -> kMutableTopLevelProperty + else -> kMutableTopLevelVariable } else when { - extensionProperty -> kExtensionProperty + extensionProperty -> kTopLevelExtensionProperty receiverType != null -> kMemberProperty - else -> kTopLevelProperty + else -> kTopLevelVariable } if (ErrorUtils.isError(classDescriptor)) { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt index dc7c5dd3052..9a2b860ecb1 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt @@ -8,6 +8,7 @@ var Int.meaning: Long fun test() { val f = String::countCharacters + f : KTopLevelExtensionProperty f : KExtensionProperty f : KMutableExtensionProperty f.get("abc") : Int @@ -15,7 +16,9 @@ fun test() { val g = Int::meaning + g : KTopLevelExtensionProperty g : KExtensionProperty + g : KMutableTopLevelExtensionProperty g : KMutableExtensionProperty g.get(0) : Long g.set(1, 0L) diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt index 85ef42b4398..88ca4f1037d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt @@ -4,8 +4,11 @@ val y: String get() = "y" fun testX() { val xx = ::x xx : KMutableTopLevelProperty + xx : KMutableTopLevelVariable xx : KTopLevelProperty + xx : KTopLevelVariable xx : KMutableProperty + xx : KMutableVariable xx : KProperty xx : KCallable @@ -17,7 +20,7 @@ fun testX() { fun testY() { val yy = ::y yy : KMutableTopLevelProperty - yy : KTopLevelProperty + yy : KTopLevelVariable yy : KMutableProperty yy : KProperty yy : KCallable diff --git a/core/reflection/src/kotlin/reflect/KTopLevelExtensionProperty.kt b/core/reflection/src/kotlin/reflect/KTopLevelExtensionProperty.kt new file mode 100644 index 00000000000..9771d4ffbbd --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KTopLevelExtensionProperty.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KTopLevelExtensionProperty : KExtensionProperty, KTopLevelProperty + +public trait KMutableTopLevelExtensionProperty : KTopLevelExtensionProperty, KMutableExtensionProperty, KMutableTopLevelProperty diff --git a/core/reflection/src/kotlin/reflect/KTopLevelProperty.kt b/core/reflection/src/kotlin/reflect/KTopLevelProperty.kt index ee1bf17b6b7..2a10126ba66 100644 --- a/core/reflection/src/kotlin/reflect/KTopLevelProperty.kt +++ b/core/reflection/src/kotlin/reflect/KTopLevelProperty.kt @@ -16,6 +16,6 @@ package kotlin.reflect -public trait KTopLevelProperty : KVariable +public trait KTopLevelProperty : KProperty -public trait KMutableTopLevelProperty : KTopLevelProperty, KMutableVariable +public trait KMutableTopLevelProperty : KTopLevelProperty, KMutableProperty diff --git a/core/reflection/src/kotlin/reflect/KTopLevelVariable.kt b/core/reflection/src/kotlin/reflect/KTopLevelVariable.kt new file mode 100644 index 00000000000..c7239c73b07 --- /dev/null +++ b/core/reflection/src/kotlin/reflect/KTopLevelVariable.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +public trait KTopLevelVariable : KVariable, KTopLevelProperty + +public trait KMutableTopLevelVariable : KTopLevelVariable, KMutableVariable, KMutableTopLevelProperty diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt similarity index 82% rename from core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt rename to core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt index 50406e2c72e..5e58247c5e3 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KExtensionPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt @@ -18,11 +18,11 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* -open class KExtensionPropertyImpl( +open class KTopLevelExtensionPropertyImpl( public override val name: String, protected val owner: KPackageImpl, protected val receiverClass: Class -) : KExtensionProperty, KPropertyImpl { +) : KTopLevelExtensionProperty, KPropertyImpl { override val field: Field? get() = null // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields @@ -33,11 +33,11 @@ open class KExtensionPropertyImpl( } } -class KMutableExtensionPropertyImpl( +class KMutableTopLevelExtensionPropertyImpl( name: String, owner: KPackageImpl, receiverClass: Class -) : KMutableExtensionProperty, KMutablePropertyImpl, KExtensionPropertyImpl(name, owner, receiverClass) { +) : KMutableTopLevelExtensionProperty, KMutablePropertyImpl, KTopLevelExtensionPropertyImpl(name, owner, receiverClass) { override val setter: Method = owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!) override fun set(receiver: T, value: R) { diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt similarity index 85% rename from core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt rename to core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt index a95bed1131f..eb765c13d08 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt @@ -18,10 +18,10 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* -open class KTopLevelPropertyImpl( +open class KTopLevelVariableImpl( public override val name: String, protected val owner: KPackageImpl -) : KTopLevelProperty, KVariableImpl { +) : KTopLevelVariable, KVariableImpl { // TODO: load the field from the corresponding package part override val field: Field? get() = null @@ -33,10 +33,10 @@ open class KTopLevelPropertyImpl( } } -class KMutableTopLevelPropertyImpl( +class KMutableTopLevelVariableImpl( name: String, owner: KPackageImpl -) : KMutableTopLevelProperty, KMutableVariableImpl, KTopLevelPropertyImpl(name, owner) { +) : KMutableTopLevelVariable, KMutableVariableImpl, KTopLevelVariableImpl(name, owner) { override val setter: Method = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) override fun set(value: R) { diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt index 9ec07585bef..07c18b226ef 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt @@ -23,14 +23,14 @@ fun kClass(jClass: Class): KClassImpl = fun kPackage(jClass: Class<*>): KPackageImpl = KPackageImpl(jClass) -fun topLevelProperty(name: String, owner: KPackageImpl): KTopLevelPropertyImpl = - KTopLevelPropertyImpl(name, owner) +fun topLevelVariable(name: String, owner: KPackageImpl): KTopLevelVariableImpl = + KTopLevelVariableImpl(name, owner) -fun mutableTopLevelProperty(name: String, owner: KPackageImpl): KMutableTopLevelPropertyImpl = - KMutableTopLevelPropertyImpl(name, owner) +fun mutableTopLevelVariable(name: String, owner: KPackageImpl): KMutableTopLevelVariableImpl = + KMutableTopLevelVariableImpl(name, owner) -fun extensionProperty(name: String, owner: KPackageImpl, receiver: Class): KExtensionPropertyImpl = - KExtensionPropertyImpl(name, owner, receiver) +fun topLevelExtensionProperty(name: String, owner: KPackageImpl, receiver: Class): KTopLevelExtensionPropertyImpl = + KTopLevelExtensionPropertyImpl(name, owner, receiver) -fun mutableExtensionProperty(name: String, owner: KPackageImpl, receiver: Class): KMutableExtensionPropertyImpl = - KMutableExtensionPropertyImpl(name, owner, receiver) +fun mutableTopLevelExtensionProperty(name: String, owner: KPackageImpl, receiver: Class): KMutableTopLevelExtensionPropertyImpl = + KMutableTopLevelExtensionPropertyImpl(name, owner, receiver) From a38a396a435e6db6cf99e03fe82079a71feed695 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 1 Jul 2014 17:42:35 +0400 Subject: [PATCH 31/38] Remove default import "kotlin.reflect" Basic reflection is usable without any imports (with :: literals) This reverts commit 9503056dd5ca70a90d1f3aff7da67a04a4d4f027. --- .../jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java | 3 +-- .../property/kClassInstanceIsInitializedFirst.kt | 2 ++ .../callableReference/property/privateClassVal.kt | 1 + .../callableReference/property/privateClassVar.kt | 1 + .../callableReference/function/constructorFromClass.kt | 2 ++ .../callableReference/function/constructorFromExtension.kt | 2 ++ .../function/constructorFromExtensionInClass.kt | 2 ++ .../callableReference/function/constructorFromTopLevel.kt | 2 ++ .../callableReference/function/differentPackageClass.kt | 2 ++ .../callableReference/function/differentPackageExtension.kt | 2 ++ .../callableReference/function/differentPackageTopLevel.kt | 2 ++ .../callableReference/function/extensionFromClass.kt | 2 ++ .../callableReference/function/extensionFromExtension.kt | 2 ++ .../function/extensionFromExtensionInClass.kt | 2 ++ .../callableReference/function/extensionFromTopLevel.kt | 2 ++ .../callableReference/function/extensionOnNullable.kt | 2 ++ .../callableReference/function/genericClassFromTopLevel.kt | 2 ++ .../callableReference/function/innerConstructorFromClass.kt | 2 ++ .../function/innerConstructorFromExtension.kt | 2 ++ .../callableReference/function/innerConstructorFromTopLevel.kt | 2 ++ .../callableReference/function/localConstructor.kt | 2 ++ .../function/localConstructorFromExtensionInLocalClass.kt | 2 ++ .../function/localConstructorFromLocalClass.kt | 2 ++ .../function/localConstructorFromLocalExtension.kt | 2 ++ .../callableReference/function/localNamedFun.kt | 2 ++ .../function/localNamedFunFromExtensionInLocalClass.kt | 2 ++ .../callableReference/function/localNamedFunFromLocalClass.kt | 2 ++ .../function/localNamedFunFromLocalExtension.kt | 2 ++ .../callableReference/function/longQualifiedName.kt | 2 ++ .../callableReference/function/longQualifiedNameGeneric.kt | 2 ++ .../callableReference/function/memberFromClass.kt | 2 ++ .../callableReference/function/memberFromExtension.kt | 2 ++ .../callableReference/function/memberFromExtensionInClass.kt | 2 ++ .../callableReference/function/memberFromTopLevel.kt | 2 ++ .../callableReference/function/nestedConstructorFromClass.kt | 2 ++ .../function/nestedConstructorFromExtension.kt | 2 ++ .../function/nestedConstructorFromTopLevel.kt | 2 ++ .../callableReference/function/noAmbiguityMemberVsExtension.kt | 2 ++ .../callableReference/function/noAmbiguityMemberVsTopLevel.kt | 2 ++ .../callableReference/function/renameOnImport.kt | 2 ++ .../callableReference/function/topLevelFromClass.kt | 2 ++ .../callableReference/function/topLevelFromExtension.kt | 2 ++ .../callableReference/function/topLevelFromExtensionInClass.kt | 2 ++ .../callableReference/function/topLevelFromTopLevel.kt | 2 ++ .../property/abstractPropertyViaSubclasses.kt | 2 ++ .../callableReference/property/accessViaSubclass.kt | 2 ++ .../callableReference/property/classFromClass.kt | 2 ++ .../callableReference/property/extensionFromClass.kt | 2 ++ .../callableReference/property/extensionFromTopLevel.kt | 2 ++ .../testsWithStdLib/callableReference/property/genericClass.kt | 2 ++ .../callableReference/property/javaInstanceField.kt | 2 ++ .../callableReference/property/javaStaticFieldViaImport.kt | 2 ++ .../callableReference/property/memberFromExtension.kt | 2 ++ .../callableReference/property/memberFromTopLevel.kt | 2 ++ .../callableReference/property/topLevelFromTopLevel.kt | 2 ++ .../src/kotlin/reflect/jvm/internal/KCallableImpl.kt | 2 ++ core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt | 2 ++ .../src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt | 1 + .../src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt | 1 + .../src/kotlin/reflect/jvm/internal/KPackageImpl.kt | 1 + .../src/kotlin/reflect/jvm/internal/KPropertyImpl.kt | 1 + .../reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt | 1 + .../src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt | 1 + .../src/kotlin/reflect/jvm/internal/KVariableImpl.kt | 2 ++ core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt | 1 + core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt | 1 + .../src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java | 3 +-- 67 files changed, 122 insertions(+), 4 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java index 21ec18286c0..3219774c4b2 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java @@ -57,8 +57,7 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { new ImportPath("java.lang.*"), new ImportPath("kotlin.*"), new ImportPath("kotlin.jvm.*"), - new ImportPath("kotlin.io.*"), - new ImportPath("kotlin.reflect.*") + new ImportPath("kotlin.io.*") ); public static class JvmSetup extends BasicSetup { diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt index cc80b293bf7..d83348c141c 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/kClassInstanceIsInitializedFirst.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberProperty + class A { class object { val ref: KMemberProperty = A::foo diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt index 21971bd98a0..a762b05c1df 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt @@ -1,3 +1,4 @@ +import kotlin.reflect.KMemberProperty import kotlin.reflect.jvm.accessible class Result { diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt index 25d98f9e51a..19a42534cb0 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt @@ -1,3 +1,4 @@ +import kotlin.reflect.KMutableMemberProperty import kotlin.reflect.jvm.accessible class A { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromClass.kt index 11bb1bd83fc..462064ebe54 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + class A { fun main() { val x = ::A diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromExtension.kt index c23a053d56d..fcbf938987f 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + class A class B diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromExtensionInClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromExtensionInClass.kt index fa6faa6831e..3b8fe60c2ba 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromExtensionInClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromExtensionInClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + class A class B { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromTopLevel.kt index e1df8095685..8ce80f50e2b 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + class A fun main() { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageClass.kt index 025c7684eea..52f172c7abf 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageClass.kt @@ -12,6 +12,8 @@ class A { package other +import kotlin.reflect.* + import first.A fun main() { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageExtension.kt index 1e7843a21a2..f38f0066a55 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageExtension.kt @@ -12,6 +12,8 @@ fun A.baz() {} package other +import kotlin.reflect.KExtensionFunction0 + import first.A import first.foo diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageTopLevel.kt index b00730fd8d5..9ae2ffb4b6f 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/differentPackageTopLevel.kt @@ -10,6 +10,8 @@ fun baz() = "OK" package other +import kotlin.reflect.* + import first.foo import first.bar import first.baz diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromClass.kt index 1d0677bd72b..28a873e4de2 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { fun main() { val x = ::foo diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromExtension.kt index 36ded52ce56..14c0c8d8e07 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A fun A.main() { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromExtensionInClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromExtensionInClass.kt index 6140d60cfa3..c3007c9c8d1 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromExtensionInClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromExtensionInClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class B class A { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromTopLevel.kt index ce3c841e007..65b9ae17169 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A fun A.foo() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionOnNullable.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionOnNullable.kt index f6fb90d4f42..2651906c74d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionOnNullable.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionOnNullable.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { fun foo() {} } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/genericClassFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/genericClassFromTopLevel.kt index 3486f124379..2d8d3ebcb59 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/genericClassFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/genericClassFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberFunction0 + class A(val t: T) { fun foo(): T = t } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromClass.kt index 72a822aefa6..d9054508aab 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberFunction0 + class A { inner class Inner diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromExtension.kt index 41425e238cb..c5d6df1fda4 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberFunction0 + class A { inner class Inner } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromTopLevel.kt index 578e4af8c80..e34e9399877 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/innerConstructorFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberFunction0 + class A { inner class Inner } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructor.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructor.kt index 17b77ce4c47..68c1740041f 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructor.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructor.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + fun main() { class A diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromExtensionInLocalClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromExtensionInLocalClass.kt index 51b7e12ce2c..4ef1b50c476 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromExtensionInLocalClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromExtensionInLocalClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + fun main() { class A diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromLocalClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromLocalClass.kt index 9b9803bf138..0bcab8a24d6 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromLocalClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromLocalClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + fun main() { class A diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromLocalExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromLocalExtension.kt index 8265c3f8b34..3f14d265479 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromLocalExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localConstructorFromLocalExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + fun main() { class A diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFun.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFun.kt index 635d0f5dad0..14620b7956e 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFun.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFun.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + fun main() { fun foo() {} fun bar(x: Int) {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromExtensionInLocalClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromExtensionInLocalClass.kt index c9667d03acc..bdcd5d1a5ff 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromExtensionInLocalClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromExtensionInLocalClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A fun main() { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromLocalClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromLocalClass.kt index 75887872fee..63bda446c3a 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromLocalClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromLocalClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + fun main() { fun foo() {} fun bar(x: Int) {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromLocalExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromLocalExtension.kt index e98cf12bdb7..38f840c4c01 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromLocalExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/localNamedFunFromLocalExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A fun main() { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/longQualifiedName.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/longQualifiedName.kt index 58aec0eb4db..0ab329ba58b 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/longQualifiedName.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/longQualifiedName.kt @@ -8,6 +8,8 @@ class D { // FILE: b.kt +import kotlin.reflect.KMemberFunction0 + fun main() { val x = a.b.c.D::foo diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/longQualifiedNameGeneric.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/longQualifiedNameGeneric.kt index 78b70bd0dbd..2c7a0a4113d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/longQualifiedNameGeneric.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/longQualifiedNameGeneric.kt @@ -8,6 +8,8 @@ class D { // FILE: b.kt +import kotlin.reflect.KMemberFunction2 + fun main() { val x = a.b.c.D::foo diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromClass.kt index 1cf9d13122f..ff31682084e 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { fun foo() {} fun bar(x: Int) {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromExtension.kt index 4b49761e193..548a84bf43b 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { fun foo() {} fun bar(x: Int) {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromExtensionInClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromExtensionInClass.kt index 8dc01bad473..83705355ae4 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromExtensionInClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromExtensionInClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { fun foo() {} fun bar(x: Int) {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromTopLevel.kt index a54d91d3d42..22162d65a52 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/memberFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { fun foo() {} fun bar(x: Int) {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromClass.kt index a51da3e20b5..2cdcc7910eb 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + class A { class Nested diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromExtension.kt index c874250ee53..007cf137c21 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + class A { class Nested } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromTopLevel.kt index 9bf36c2d77a..d464aa9de07 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/nestedConstructorFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KFunction0 + class A { class Nested } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/noAmbiguityMemberVsExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/noAmbiguityMemberVsExtension.kt index 273da3b2b73..b3e8a6756af 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/noAmbiguityMemberVsExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/noAmbiguityMemberVsExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberFunction0 + class A { fun foo() = 42 } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/noAmbiguityMemberVsTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/noAmbiguityMemberVsTopLevel.kt index bb33818fe4b..b6f1f6a9d49 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/noAmbiguityMemberVsTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/noAmbiguityMemberVsTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberFunction0 + fun foo() {} class A { diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/renameOnImport.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/renameOnImport.kt index 1dae56d6c7b..d71da504022 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/renameOnImport.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/renameOnImport.kt @@ -12,6 +12,8 @@ fun A.baz(x: String) {} // FILE: b.kt +import kotlin.reflect.* + import other.foo as foofoo import other.A as AA import other.baz as bazbaz diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromClass.kt index 7c3660f0ce3..25908ce1b8b 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + fun foo() {} fun bar(x: Int) {} fun baz() = "OK" diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromExtension.kt index f18c7b46a44..c39d37b241d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A fun foo() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromExtensionInClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromExtensionInClass.kt index bffbab043f6..7d717d2d4e6 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromExtensionInClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromExtensionInClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A fun foo() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromTopLevel.kt index fc7d114c8bf..f3d0b9a7bd3 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/topLevelFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + fun foo() {} fun bar(x: Int) {} fun baz() = "OK" diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt index 5054f0a717c..55c17425814 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/abstractPropertyViaSubclasses.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberProperty + trait Base { val x: Any } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt index d3081f85a95..8c533fbc044 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/accessViaSubclass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberProperty + open class Base { val foo: Int = 42 } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt index f99c615756a..f4686a586d8 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/classFromClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A(var g: A) { val f: Int = 0 diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt index 581b698c8e4..a15f054d3ff 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { fun test() { ::foo : KExtensionProperty diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt index 9a2b860ecb1..3fcedb39072 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/extensionFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + val String.countCharacters: Int get() = length diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt index 4e89f7155d6..9b1ff0d1b05 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/genericClass.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.KMemberProperty + class A(val t: T) { val foo: T = t } diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt index fa2f1f436ec..18ec86372b4 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaInstanceField.kt @@ -13,6 +13,8 @@ public class JavaClass { // FILE: test.kt +import kotlin.reflect.* + fun test() { JavaClass::publicFinal : KMemberProperty JavaClass::publicMutable : KMutableMemberProperty diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt index 555b296f0c6..51bb4a55793 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/javaStaticFieldViaImport.kt @@ -15,6 +15,8 @@ public class JavaClass { import JavaClass.* +import kotlin.reflect.* + fun test() { ::publicFinal : KTopLevelProperty ::publicMutable : KMutableTopLevelProperty diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt index 091e60a2893..624022a2b87 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromExtension.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { val foo: Unit = Unit.VALUE var bar: String = "" diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt index 93e5bb0601c..a95d1dbfc39 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/memberFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + class A { val foo: Int = 42 var bar: String = "" diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt index 88ca4f1037d..8069c3ae562 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/property/topLevelFromTopLevel.kt @@ -1,3 +1,5 @@ +import kotlin.reflect.* + var x: Int = 42 val y: String get() = "y" diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt index 0164fcbc513..99ccfa51476 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -16,4 +16,6 @@ package kotlin.reflect.jvm.internal +import kotlin.reflect.KCallable + trait KCallableImpl : KCallable diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index ca2f4efba63..442d7f9fcb6 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -16,6 +16,8 @@ package kotlin.reflect.jvm.internal +import kotlin.reflect.* + enum class KClassOrigin { BUILT_IN KOTLIN diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt index 97ef4430acf..1aa2139d374 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt @@ -17,6 +17,7 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* +import kotlin.reflect.* open class KForeignMemberProperty( public override val name: String, diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index d237f450004..3872a48bf3d 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -17,6 +17,7 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* +import kotlin.reflect.* // TODO: properties of built-in classes diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index 1bd38d78641..c19eafafd96 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -15,6 +15,7 @@ */ package kotlin.reflect.jvm.internal +import kotlin.reflect.* class KPackageImpl( val jClass: Class<*> diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt index 335a159eeb5..76b1e61f29f 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -17,6 +17,7 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* +import kotlin.reflect.* trait KPropertyImpl : KProperty, KCallableImpl { val field: Field? diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt index 5e58247c5e3..07b4ef66c4f 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt @@ -17,6 +17,7 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* +import kotlin.reflect.* open class KTopLevelExtensionPropertyImpl( public override val name: String, diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt index eb765c13d08..ba15cb675f2 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt @@ -17,6 +17,7 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* +import kotlin.reflect.* open class KTopLevelVariableImpl( public override val name: String, diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt index 5fac1d5141a..1dacc258385 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt @@ -16,6 +16,8 @@ package kotlin.reflect.jvm.internal +import kotlin.reflect.* + trait KVariableImpl : KVariable, KPropertyImpl trait KMutableVariableImpl : KMutableVariable, KVariableImpl, KMutablePropertyImpl diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt index 07c18b226ef..5fa0730bf36 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt @@ -16,6 +16,7 @@ package kotlin.reflect.jvm.internal +import kotlin.reflect.* fun kClass(jClass: Class): KClassImpl = KClassImpl(jClass) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt index 1c7825f0489..20df3d6b801 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt @@ -16,6 +16,7 @@ package kotlin.reflect.jvm +import kotlin.reflect.* import kotlin.reflect.jvm.internal.* public var KProperty.accessible: Boolean diff --git a/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java b/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java index 0b01f55f84b..bfdd2a91803 100644 --- a/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java +++ b/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java @@ -49,8 +49,7 @@ public final class AnalyzerFacadeForJS { public static final List DEFAULT_IMPORTS = ImmutableList.of( new ImportPath("js.*"), new ImportPath("java.lang.*"), - new ImportPath("kotlin.*"), - new ImportPath("kotlin.reflect.*") + new ImportPath("kotlin.*") ); private AnalyzerFacadeForJS() { From f459005fe769990486c695374d3b17b17c8e07c0 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 1 Jul 2014 20:12:12 +0400 Subject: [PATCH 32/38] Fix GeneratedClassLoader so that it loads Package instances --- .../org/jetbrains/jet/codegen/GeneratedClassLoader.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java index 0a0e865c863..70e6627821a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java @@ -22,6 +22,7 @@ import org.jetbrains.jet.OutputFile; import java.net.URL; import java.net.URLClassLoader; import java.util.List; +import java.util.jar.Manifest; public class GeneratedClassLoader extends URLClassLoader { private ClassFileFactory state; @@ -39,6 +40,13 @@ public class GeneratedClassLoader extends URLClassLoader { OutputFile outputFile = state.get(classFilePath); if (outputFile != null) { byte[] bytes = outputFile.asByteArray(); + int lastDot = name.lastIndexOf('.'); + if (lastDot >= 0) { + String pkgName = name.substring(0, lastDot); + if (getPackage(pkgName) == null) { + definePackage(pkgName, new Manifest(), null); + } + } return defineClass(name, bytes, 0, bytes.length); } From c575ad9fb00b4142ca986b1988720f42300b74bd Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 1 Jul 2014 21:01:07 +0400 Subject: [PATCH 33/38] Fix test, remove duplicate annotation It started to fail only now because KClassImpl constructor is now loading class' annotations (previously annotations weren't loaded by Java reflection) --- .../KotlinPropertyAsAnnotationParameter.B.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/testData/compileKotlinAgainstKotlin/KotlinPropertyAsAnnotationParameter.B.kt b/compiler/testData/compileKotlinAgainstKotlin/KotlinPropertyAsAnnotationParameter.B.kt index efa50fe6ebf..32e6000ec7a 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/KotlinPropertyAsAnnotationParameter.B.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/KotlinPropertyAsAnnotationParameter.B.kt @@ -3,8 +3,10 @@ import java.lang.annotation.RetentionPolicy import a.* Ann(i, s, f, d, l, b, bool, c, str) +class MyClass1 + Ann(i2, s2, f2, d2, l2, b2, bool2, c2, str2) -class MyClass +class MyClass2 Retention(RetentionPolicy.RUNTIME) annotation class Ann( @@ -20,7 +22,7 @@ annotation class Ann( ) fun main(args: Array) { - MyClass() + // Trigger annotation loading + (MyClass1() as java.lang.Object).getClass().getAnnotations() + (MyClass2() as java.lang.Object).getClass().getAnnotations() } - - From 704de8992eb979640f06e3ef836c8373e51e7b42 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 20 Jun 2014 19:22:02 +0400 Subject: [PATCH 34/38] Support mapping between Java and Kotlin reflection objects --- .../jet/compiler/android/SpecialFiles.java | 6 +- .../reflection/mapping/jClass2kClass.java | 1 + .../reflection/mapping/jClass2kClass.kt | 11 + .../reflection/mapping/javaFields.java | 9 + .../reflection/mapping/javaFields.kt | 43 ++++ .../insideLambda/classInLambda.kt | 0 .../insideLambda/objectInLambda.kt | 0 .../lambda/lambdaInConstructor.kt | 0 .../lambda/lambdaInFunction.kt | 0 .../{ => enclosing}/lambda/lambdaInLambda.kt | 0 .../lambda/lambdaInLocalClass.kt | 0 .../lambda/lambdaInLocalFunction.kt | 0 .../lambda/lambdaInMemberFunction.kt | 0 .../lambdaInMemberFunctionInLocalClass.kt | 0 .../lambdaInMemberFunctionInNestedClass.kt | 0 .../lambda/lambdaInObjectExpression.kt | 0 .../{ => enclosing}/lambda/lambdaInPackage.kt | 0 .../lambda/lambdaInPropertyGetter.kt | 0 .../lambda/lambdaInPropertySetter.kt | 0 .../{ => genericSignature}/kt5112.kt | 0 .../reflection/mapping/extensionProperty.kt | 27 +++ .../reflection/mapping/memberProperty.kt | 23 ++ .../reflection/mapping/package.kt | 13 ++ .../reflection/mapping/topLevelProperty.kt | 23 ++ .../AbstractBlackBoxCodegenTest.java | 3 +- ...ackBoxAgainstJavaCodegenTestGenerated.java | 36 +++- ...lackBoxWithStdlibCodegenTestGenerated.java | 201 +++++++++++------- .../src/kotlin/jvm/internal/Intrinsic.kt | 22 ++ .../kotlin/reflect/jvm/internal/KClassImpl.kt | 6 +- .../reflect/jvm/internal/KPackageImpl.kt | 7 +- .../src/kotlin/reflect/jvm/internal/util.kt | 6 + .../src/kotlin/reflect/jvm/mapping.kt | 84 ++++++++ .../src/kotlin/jvm/internal/Intrinsic.kt | 6 - 33 files changed, 434 insertions(+), 93 deletions(-) create mode 100644 compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.java create mode 100644 compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.kt create mode 100644 compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.java create mode 100644 compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/insideLambda/classInLambda.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/insideLambda/objectInLambda.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInConstructor.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInFunction.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInLambda.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInLocalClass.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInLocalFunction.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInMemberFunction.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInMemberFunctionInLocalClass.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInMemberFunctionInNestedClass.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInObjectExpression.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInPackage.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInPropertyGetter.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => enclosing}/lambda/lambdaInPropertySetter.kt (100%) rename compiler/testData/codegen/boxWithStdlib/reflection/{ => genericSignature}/kt5112.kt (100%) create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/mapping/extensionProperty.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/mapping/memberProperty.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/mapping/package.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/Intrinsic.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/mapping.kt delete mode 100644 libraries/stdlib/src/kotlin/jvm/internal/Intrinsic.kt diff --git a/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java index d162776ed5a..045a3426999 100644 --- a/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java +++ b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java @@ -61,6 +61,7 @@ public class SpecialFiles { excludedFiles.add("boxMultiFile"); // MultiFileTest not supported yet excludedFiles.add("boxInline"); // MultiFileTest not supported yet + excludedFiles.add("reflection"); excludedFiles.add("kt3238.kt"); // Reflection excludedFiles.add("kt1482_2279.kt"); // Reflection @@ -69,11 +70,6 @@ public class SpecialFiles { excludedFiles.add("packageQualifiedMethod.kt"); // Cannot change package name excludedFiles.add("classObjectToString.kt"); // Cannot change package name - /* Reflection tests with full-qualified names*/ - excludedFiles.add("insideLambda"); - excludedFiles.add("lambda"); - excludedFiles.add("kt5112.kt"); - excludedFiles.add("kt326.kt"); // Commented excludedFiles.add("kt1213.kt"); // Commented diff --git a/compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.java b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.java new file mode 100644 index 00000000000..0256b2f75f7 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.java @@ -0,0 +1 @@ +public class jClass2kClass {} diff --git a/compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.kt b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.kt new file mode 100644 index 00000000000..414ae0ca5e1 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.kt @@ -0,0 +1,11 @@ +import jClass2kClass as J + +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun box(): String { + val j = javaClass() + assertEquals(j, j.kotlin.java) + + return "OK" +} diff --git a/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.java b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.java new file mode 100644 index 00000000000..0377951bd4b --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.java @@ -0,0 +1,9 @@ +public class javaFields { + public final int i; + public String s; + + public javaFields(int i, String s) { + this.i = i; + this.s = s; + } +} diff --git a/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt new file mode 100644 index 00000000000..a5de7e5bf12 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt @@ -0,0 +1,43 @@ +import javaFields as J + +import java.lang.reflect.* +import kotlin.reflect.* +import kotlin.reflect.jvm.* + +fun box(): String { + val i = J::i + val s = J::s + + // Check that correct reflection objects are created + assert(i.javaClass.getSimpleName() == "KForeignMemberProperty", "Fail i class") + assert(s.javaClass.getSimpleName() == "KMutableForeignMemberProperty", "Fail s class") + + // Check that no Method objects are created for such properties + assert(i.javaGetter == null, "Fail i getter") + assert(s.javaGetter == null, "Fail s getter") + assert(s.javaSetter == null, "Fail s setter") + + // Check that correct Field objects are created + val ji = i.javaField!! + val js = s.javaField!! + assert(Modifier.isFinal(ji.getModifiers()), "Fail i final") + assert(!Modifier.isFinal(js.getModifiers()), "Fail s final") + + // Check that those Field objects work as expected + val a = J(42, "abc") + assert(ji.get(a) == 42, "Fail ji get") + assert(js.get(a) == "abc", "Fail js get") + js.set(a, "def") + assert(js.get(a) == "def", "Fail js set") + assert(a.s == "def", "Fail js access") + + // Check that valid Kotlin reflection objects are created by those Field objects + val ki = ji.kotlin as KMemberProperty + val ks = js.kotlin as KMutableMemberProperty + assert(ki.get(a) == 42, "Fail ki get") + assert(ks.get(a) == "def", "Fail ks get") + ks.set(a, "ghi") + assert(ks.get(a) == "ghi", "Fail ks set") + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/insideLambda/classInLambda.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda/classInLambda.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/insideLambda/classInLambda.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda/classInLambda.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/insideLambda/objectInLambda.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda/objectInLambda.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/insideLambda/objectInLambda.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda/objectInLambda.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInConstructor.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInConstructor.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInConstructor.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInConstructor.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInFunction.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInFunction.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInFunction.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInFunction.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLambda.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLambda.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLambda.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLambda.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLocalClass.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalClass.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLocalClass.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalClass.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLocalFunction.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalFunction.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLocalFunction.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalFunction.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunction.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunction.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunction.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunction.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunctionInLocalClass.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunctionInLocalClass.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunctionInLocalClass.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunctionInLocalClass.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunctionInNestedClass.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunctionInNestedClass.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunctionInNestedClass.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunctionInNestedClass.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInObjectExpression.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInObjectExpression.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInObjectExpression.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInObjectExpression.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPackage.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPackage.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPackage.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPackage.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPropertyGetter.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPropertyGetter.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPropertyGetter.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPropertyGetter.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPropertySetter.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPropertySetter.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPropertySetter.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPropertySetter.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/kt5112.kt b/compiler/testData/codegen/boxWithStdlib/reflection/genericSignature/kt5112.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/kt5112.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/genericSignature/kt5112.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/extensionProperty.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/extensionProperty.kt new file mode 100644 index 00000000000..9d470a193d0 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/extensionProperty.kt @@ -0,0 +1,27 @@ +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +class K(var value: Long) + +var K.ext: Double + get() = value.toDouble() + set(value) { + this.value = value.toLong() + } + +fun box(): String { + val p = K::ext + + val getter = p.javaGetter!! + val setter = p.javaSetter!! + + assertEquals(getter, Class.forName("_DefaultPackage").getMethod("getExt", javaClass())) + assertEquals(setter, Class.forName("_DefaultPackage").getMethod("setExt", javaClass(), javaClass())) + + val k = K(42L) + assert(getter.invoke(null, k) == 42.0, "Fail k getter") + setter.invoke(null, k, -239.0) + assert(getter.invoke(null, k) == -239.0, "Fail k setter") + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/memberProperty.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/memberProperty.kt new file mode 100644 index 00000000000..e39bb09d767 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/memberProperty.kt @@ -0,0 +1,23 @@ +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +class K(var value: Long) + +fun box(): String { + val p = K::value + + assert(p.javaField != null, "Fail p field") + + val getter = p.javaGetter!! + val setter = p.javaSetter!! + + assertEquals(getter, javaClass().getMethod("getValue")) + assertEquals(setter, javaClass().getMethod("setValue", javaClass())) + + val k = K(42L) + assert(getter.invoke(k) == 42L, "Fail k getter") + setter.invoke(k, -239L) + assert(getter.invoke(k) == -239L, "Fail k setter") + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/package.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/package.kt new file mode 100644 index 00000000000..07d168a5a55 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/package.kt @@ -0,0 +1,13 @@ +package test + +import kotlin.reflect.jvm.* +import kotlin.test.* + +fun box(): String { + val facadeJClass = Class.forName("test.TestPackage") as Class + + assertEquals(facadeJClass, facadeJClass.kotlinPackage.javaFacade) + assertEquals(facadeJClass, facadeJClass.kotlin.java) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt new file mode 100644 index 00000000000..ada90d5c564 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt @@ -0,0 +1,23 @@ +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +var topLevel = "123" + +fun box(): String { + val p = ::topLevel + + // TODO: uncomment when fields are loaded from package parts + // assert(p.javaField != null, "Fail p field") + + val getter = p.javaGetter!! + val setter = p.javaSetter!! + + assertEquals(getter, Class.forName("_DefaultPackage").getMethod("getTopLevel")) + assertEquals(setter, Class.forName("_DefaultPackage").getMethod("setTopLevel", javaClass())) + + assert(getter.invoke(null) == "123", "Fail k getter") + setter.invoke(null, "456") + assert(getter.invoke(null) == "456", "Fail k setter") + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/AbstractBlackBoxCodegenTest.java b/compiler/tests/org/jetbrains/jet/codegen/generated/AbstractBlackBoxCodegenTest.java index 637e5a27c34..bc086effe2a 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/AbstractBlackBoxCodegenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/AbstractBlackBoxCodegenTest.java @@ -97,7 +97,8 @@ public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase { File javaClassesTempDirectory = compileJava(ktFile.replaceFirst("\\.kt$", ".java")); myEnvironment = JetCoreEnvironment.createForTests(getTestRootDisposable(), JetTestUtils.compilerConfigurationForTests( - ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, JetTestUtils.getAnnotationsJar(), javaClassesTempDirectory)); + ConfigurationKind.ALL, TestJdkKind.FULL_JDK, JetTestUtils.getAnnotationsJar(), javaClassesTempDirectory + )); loadFile(ktFile); blackBox(); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java index 22a8556dee2..ae1fa6b0a62 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.codegen.generated.AbstractBlackBoxCodegenTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/boxAgainstJava") -@InnerTestClasses({BlackBoxAgainstJavaCodegenTestGenerated.Annotations.class, BlackBoxAgainstJavaCodegenTestGenerated.CallableReference.class, BlackBoxAgainstJavaCodegenTestGenerated.Constructor.class, BlackBoxAgainstJavaCodegenTestGenerated.Delegation.class, BlackBoxAgainstJavaCodegenTestGenerated.Enum.class, BlackBoxAgainstJavaCodegenTestGenerated.Functions.class, BlackBoxAgainstJavaCodegenTestGenerated.InnerClass.class, BlackBoxAgainstJavaCodegenTestGenerated.Property.class, BlackBoxAgainstJavaCodegenTestGenerated.Sam.class, BlackBoxAgainstJavaCodegenTestGenerated.StaticFun.class, BlackBoxAgainstJavaCodegenTestGenerated.Visibility.class}) +@InnerTestClasses({BlackBoxAgainstJavaCodegenTestGenerated.Annotations.class, BlackBoxAgainstJavaCodegenTestGenerated.CallableReference.class, BlackBoxAgainstJavaCodegenTestGenerated.Constructor.class, BlackBoxAgainstJavaCodegenTestGenerated.Delegation.class, BlackBoxAgainstJavaCodegenTestGenerated.Enum.class, BlackBoxAgainstJavaCodegenTestGenerated.Functions.class, BlackBoxAgainstJavaCodegenTestGenerated.InnerClass.class, BlackBoxAgainstJavaCodegenTestGenerated.Property.class, BlackBoxAgainstJavaCodegenTestGenerated.Reflection.class, BlackBoxAgainstJavaCodegenTestGenerated.Sam.class, BlackBoxAgainstJavaCodegenTestGenerated.StaticFun.class, BlackBoxAgainstJavaCodegenTestGenerated.Visibility.class}) public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInBoxAgainstJava() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxAgainstJava"), Pattern.compile("^(.+)\\.kt$"), true); @@ -236,6 +236,39 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/reflection") + @InnerTestClasses({Reflection.Mapping.class}) + public static class Reflection extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInReflection() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxAgainstJava/reflection"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("compiler/testData/codegen/boxAgainstJava/reflection/mapping") + public static class Mapping extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInMapping() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxAgainstJava/reflection/mapping"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("jClass2kClass.kt") + public void testJClass2kClass() throws Exception { + doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/reflection/mapping/jClass2kClass.kt"); + } + + @TestMetadata("javaFields.kt") + public void testJavaFields() throws Exception { + doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt"); + } + + } + + public static Test innerSuite() { + TestSuite suite = new TestSuite("Reflection"); + suite.addTestSuite(Reflection.class); + suite.addTestSuite(Mapping.class); + return suite; + } + } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/sam") @InnerTestClasses({Sam.Adapters.class}) public static class Sam extends AbstractBlackBoxCodegenTest { @@ -609,6 +642,7 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod suite.addTestSuite(Functions.class); suite.addTestSuite(InnerClass.class); suite.addTestSuite(Property.class); + suite.addTest(Reflection.innerSuite()); suite.addTest(Sam.innerSuite()); suite.addTestSuite(StaticFun.class); suite.addTest(Visibility.innerSuite()); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 2297e6821c8..51f5815cc53 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -1381,99 +1381,151 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection") - @InnerTestClasses({Reflection.InsideLambda.class, Reflection.Lambda.class}) + @InnerTestClasses({Reflection.Enclosing.class, Reflection.GenericSignature.class, Reflection.Mapping.class}) public static class Reflection extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInReflection() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection"), Pattern.compile("^(.+)\\.kt$"), true); } - @TestMetadata("kt5112.kt") - public void testKt5112() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/kt5112.kt"); + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing") + @InnerTestClasses({Enclosing.InsideLambda.class, Enclosing.Lambda.class}) + public static class Enclosing extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInEnclosing() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/enclosing"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda") + public static class InsideLambda extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInInsideLambda() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("classInLambda.kt") + public void testClassInLambda() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda/classInLambda.kt"); + } + + @TestMetadata("objectInLambda.kt") + public void testObjectInLambda() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda/objectInLambda.kt"); + } + + } + + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda") + public static class Lambda extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInLambda() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("lambdaInConstructor.kt") + public void testLambdaInConstructor() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInConstructor.kt"); + } + + @TestMetadata("lambdaInFunction.kt") + public void testLambdaInFunction() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInFunction.kt"); + } + + @TestMetadata("lambdaInLambda.kt") + public void testLambdaInLambda() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLambda.kt"); + } + + @TestMetadata("lambdaInLocalClass.kt") + public void testLambdaInLocalClass() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalClass.kt"); + } + + @TestMetadata("lambdaInLocalFunction.kt") + public void testLambdaInLocalFunction() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalFunction.kt"); + } + + @TestMetadata("lambdaInMemberFunction.kt") + public void testLambdaInMemberFunction() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunction.kt"); + } + + @TestMetadata("lambdaInMemberFunctionInLocalClass.kt") + public void testLambdaInMemberFunctionInLocalClass() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunctionInLocalClass.kt"); + } + + @TestMetadata("lambdaInMemberFunctionInNestedClass.kt") + public void testLambdaInMemberFunctionInNestedClass() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunctionInNestedClass.kt"); + } + + @TestMetadata("lambdaInObjectExpression.kt") + public void testLambdaInObjectExpression() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInObjectExpression.kt"); + } + + @TestMetadata("lambdaInPackage.kt") + public void testLambdaInPackage() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPackage.kt"); + } + + @TestMetadata("lambdaInPropertyGetter.kt") + public void testLambdaInPropertyGetter() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPropertyGetter.kt"); + } + + @TestMetadata("lambdaInPropertySetter.kt") + public void testLambdaInPropertySetter() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPropertySetter.kt"); + } + + } + + public static Test innerSuite() { + TestSuite suite = new TestSuite("Enclosing"); + suite.addTestSuite(Enclosing.class); + suite.addTestSuite(InsideLambda.class); + suite.addTestSuite(Lambda.class); + return suite; + } } - @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/insideLambda") - public static class InsideLambda extends AbstractBlackBoxCodegenTest { - public void testAllFilesPresentInInsideLambda() throws Exception { - JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/insideLambda"), Pattern.compile("^(.+)\\.kt$"), true); + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/genericSignature") + public static class GenericSignature extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInGenericSignature() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/genericSignature"), Pattern.compile("^(.+)\\.kt$"), true); } - @TestMetadata("classInLambda.kt") - public void testClassInLambda() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/insideLambda/classInLambda.kt"); - } - - @TestMetadata("objectInLambda.kt") - public void testObjectInLambda() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/insideLambda/objectInLambda.kt"); + @TestMetadata("kt5112.kt") + public void testKt5112() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/genericSignature/kt5112.kt"); } } - @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/lambda") - public static class Lambda extends AbstractBlackBoxCodegenTest { - public void testAllFilesPresentInLambda() throws Exception { - JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/lambda"), Pattern.compile("^(.+)\\.kt$"), true); + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping") + public static class Mapping extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInMapping() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/mapping"), Pattern.compile("^(.+)\\.kt$"), true); } - @TestMetadata("lambdaInConstructor.kt") - public void testLambdaInConstructor() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInConstructor.kt"); + @TestMetadata("extensionProperty.kt") + public void testExtensionProperty() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/mapping/extensionProperty.kt"); } - @TestMetadata("lambdaInFunction.kt") - public void testLambdaInFunction() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInFunction.kt"); + @TestMetadata("memberProperty.kt") + public void testMemberProperty() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/mapping/memberProperty.kt"); } - @TestMetadata("lambdaInLambda.kt") - public void testLambdaInLambda() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLambda.kt"); + @TestMetadata("package.kt") + public void testPackage() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/mapping/package.kt"); } - @TestMetadata("lambdaInLocalClass.kt") - public void testLambdaInLocalClass() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLocalClass.kt"); - } - - @TestMetadata("lambdaInLocalFunction.kt") - public void testLambdaInLocalFunction() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInLocalFunction.kt"); - } - - @TestMetadata("lambdaInMemberFunction.kt") - public void testLambdaInMemberFunction() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunction.kt"); - } - - @TestMetadata("lambdaInMemberFunctionInLocalClass.kt") - public void testLambdaInMemberFunctionInLocalClass() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunctionInLocalClass.kt"); - } - - @TestMetadata("lambdaInMemberFunctionInNestedClass.kt") - public void testLambdaInMemberFunctionInNestedClass() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInMemberFunctionInNestedClass.kt"); - } - - @TestMetadata("lambdaInObjectExpression.kt") - public void testLambdaInObjectExpression() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInObjectExpression.kt"); - } - - @TestMetadata("lambdaInPackage.kt") - public void testLambdaInPackage() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPackage.kt"); - } - - @TestMetadata("lambdaInPropertyGetter.kt") - public void testLambdaInPropertyGetter() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPropertyGetter.kt"); - } - - @TestMetadata("lambdaInPropertySetter.kt") - public void testLambdaInPropertySetter() throws Exception { - doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/lambda/lambdaInPropertySetter.kt"); + @TestMetadata("topLevelProperty.kt") + public void testTopLevelProperty() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt"); } } @@ -1481,8 +1533,9 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode public static Test innerSuite() { TestSuite suite = new TestSuite("Reflection"); suite.addTestSuite(Reflection.class); - suite.addTestSuite(InsideLambda.class); - suite.addTestSuite(Lambda.class); + suite.addTest(Enclosing.innerSuite()); + suite.addTestSuite(GenericSignature.class); + suite.addTestSuite(Mapping.class); return suite; } } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsic.kt b/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsic.kt new file mode 100644 index 00000000000..8fd8b0176d4 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsic.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2014 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 kotlin.jvm.internal + +import java.lang.annotation.* + +Retention(RetentionPolicy.RUNTIME) +public annotation class Intrinsic(val value: String) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 442d7f9fcb6..178806178de 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -17,6 +17,8 @@ package kotlin.reflect.jvm.internal import kotlin.reflect.* +import kotlin.jvm.internal.KotlinClass +import kotlin.jvm.internal.KotlinSyntheticClass enum class KClassOrigin { BUILT_IN @@ -24,8 +26,8 @@ enum class KClassOrigin { FOREIGN } -private val KOTLIN_CLASS_ANNOTATION_CLASS = Class.forName("kotlin.jvm.internal.KotlinClass") as Class -private val KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS = Class.forName("kotlin.jvm.internal.KotlinSyntheticClass") as Class +private val KOTLIN_CLASS_ANNOTATION_CLASS = javaClass() +private val KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS = javaClass() class KClassImpl(val jClass: Class) : KClass { // TODO: write metadata to local classes diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index c19eafafd96..7e16b2479c0 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -15,8 +15,7 @@ */ package kotlin.reflect.jvm.internal -import kotlin.reflect.* -class KPackageImpl( - val jClass: Class<*> -) : KPackage +import kotlin.reflect.KPackage + +class KPackageImpl(val jClass: Class<*>) : KPackage diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt index 84d6b0a3120..0fbf5803908 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -17,6 +17,7 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.Method +import kotlin.jvm.internal.Intrinsic // TODO: use stdlib? suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") @@ -34,6 +35,11 @@ private fun getterName(propertyName: String): String = "get" + propertyName.capi private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention() +// A local copy of javaClass() from stdlib is needed because there's no dependency on stdlib in runtime.jvm +[Intrinsic("kotlin.javaClass.function")] +fun javaClass(): Class = throw UnsupportedOperationException() + + private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: Class<*>): Method { try { return getMethod(name, *parameterTypes) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/mapping.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/mapping.kt new file mode 100644 index 00000000000..b40f1d6c24c --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/mapping.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm + +import java.lang.reflect.* +import kotlin.reflect.* +import kotlin.reflect.jvm.internal.* + +// Kotlin reflection -> Java reflection + +public val KClass.java: Class + get() = (this as KClassImpl).jClass + +public val KPackage.javaFacade: Class<*> + get() = (this as KPackageImpl).jClass + + +public val KProperty<*>.javaGetter: Method? + get() = (this as? KPropertyImpl<*>)?.getter + +public val KMutableProperty<*>.javaSetter: Method? + get() = (this as? KMutablePropertyImpl<*>)?.setter + + +// TODO: val KTopLevelVariable<*>.javaField: Field + +public val KTopLevelVariable<*>.javaGetter: Method + get() = (this as KTopLevelVariableImpl<*>).getter + +public val KMutableTopLevelVariable<*>.javaSetter: Method + get() = (this as KMutableTopLevelVariableImpl<*>).setter + + +public val KTopLevelExtensionProperty<*, *>.javaGetter: Method + get() = (this as KTopLevelExtensionPropertyImpl<*, *>).getter + +public val KMutableTopLevelExtensionProperty<*, *>.javaSetter: Method + get() = (this as KMutableTopLevelExtensionPropertyImpl<*, *>).setter + + +public val KMemberProperty<*, *>.javaField: Field? + get() = (this as KPropertyImpl<*>).field + + +// Java reflection -> Kotlin reflection + +public val Class.kotlin: KClass + get() = kClass(this) + +public val Class<*>.kotlinPackage: KPackage + get() = kPackage(this) + + +public val Field.kotlin: KProperty<*> + get() { + val clazz = getDeclaringClass() + val name = getName()!! + val modifiers = getModifiers() + val static = Modifier.isStatic(modifiers) + val final = Modifier.isFinal(modifiers) + if (static) { + val kPackage = kPackage(clazz) + return if (final) topLevelVariable(name, kPackage) else mutableTopLevelVariable(name, kPackage) + } + else { + val kClass = kClass(clazz as Class) + return if (final) kClass.memberProperty(name) else kClass.mutableMemberProperty(name) + } + } + diff --git a/libraries/stdlib/src/kotlin/jvm/internal/Intrinsic.kt b/libraries/stdlib/src/kotlin/jvm/internal/Intrinsic.kt deleted file mode 100644 index 05fc4ad46c8..00000000000 --- a/libraries/stdlib/src/kotlin/jvm/internal/Intrinsic.kt +++ /dev/null @@ -1,6 +0,0 @@ -package kotlin.jvm.internal - -import java.lang.annotation.* - -Retention(RetentionPolicy.RUNTIME) -annotation class Intrinsic(val value: String) From c5d92cc03ee96dd307feca61089eca4fef28856b Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 30 Jun 2014 19:16:59 +0400 Subject: [PATCH 35/38] Provide "equals" and "hashCode" for reflection objects --- .../methodsFromAny/equalsHashCode.kt | 29 +++++++++++++++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 16 +++++++++- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 6 ++++ .../jvm/internal/KForeignMemberProperty.kt | 6 ++++ .../jvm/internal/KMemberPropertyImpl.kt | 6 ++++ .../reflect/jvm/internal/KPackageImpl.kt | 8 ++++- .../KTopLevelExtensionPropertyImpl.kt | 6 ++++ .../jvm/internal/KTopLevelVariableImpl.kt | 6 ++++ 8 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/equalsHashCode.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/equalsHashCode.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/equalsHashCode.kt new file mode 100644 index 00000000000..476b185d961 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/equalsHashCode.kt @@ -0,0 +1,29 @@ +import kotlin.test.* + +val top = 42 +var top2 = -23 + +val Int.intExt: Int get() = this +val Char.charExt: Int get() = this.toInt() + +class A(var mem: String) +class B(var mem: String) + + +fun checkEqual(x: Any, y: Any) { + assertEquals(x, y) + assertEquals(x.hashCode(), y.hashCode(), "Elements are equal but their hash codes are not: ${x.hashCode()} != ${y.hashCode()}") +} + +fun box(): String { + checkEqual(::top, ::top) + checkEqual(::top2, ::top2) + checkEqual(Int::intExt, Int::intExt) + checkEqual(A::mem, A::mem) + + assertFalse(::top == ::top2) + assertFalse(Int::intExt == Char::charExt) + assertFalse(A::mem == B::mem) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 51f5815cc53..252025ee4ed 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -1381,7 +1381,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection") - @InnerTestClasses({Reflection.Enclosing.class, Reflection.GenericSignature.class, Reflection.Mapping.class}) + @InnerTestClasses({Reflection.Enclosing.class, Reflection.GenericSignature.class, Reflection.Mapping.class, Reflection.MethodsFromAny.class}) public static class Reflection extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInReflection() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection"), Pattern.compile("^(.+)\\.kt$"), true); @@ -1530,12 +1530,26 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny") + public static class MethodsFromAny extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInMethodsFromAny() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("equalsHashCode.kt") + public void testEqualsHashCode() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/equalsHashCode.kt"); + } + + } + public static Test innerSuite() { TestSuite suite = new TestSuite("Reflection"); suite.addTestSuite(Reflection.class); suite.addTest(Enclosing.innerSuite()); suite.addTestSuite(GenericSignature.class); suite.addTestSuite(Mapping.class); + suite.addTestSuite(MethodsFromAny.class); return suite; } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 178806178de..49f66afefc7 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -56,4 +56,10 @@ class KClassImpl(val jClass: Class) : KClass { else { KMutableForeignMemberProperty(name, this) } + + override fun equals(other: Any?): Boolean = + other is KClassImpl<*> && jClass == other.jClass + + override fun hashCode(): Int = + jClass.hashCode() } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt index 1aa2139d374..c0aab6889b1 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt @@ -30,6 +30,12 @@ open class KForeignMemberProperty( override fun get(receiver: T): R { return field.get(receiver) as R } + + override fun equals(other: Any?): Boolean = + other is KForeignMemberProperty<*, *> && name == other.name && owner == other.owner + + override fun hashCode(): Int = + name.hashCode() * 31 + owner.hashCode() } class KMutableForeignMemberProperty( diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 3872a48bf3d..8135c7dfea2 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -39,6 +39,12 @@ open class KMemberPropertyImpl( override fun get(receiver: T): R { return getter(receiver) as R } + + override fun equals(other: Any?): Boolean = + other is KMemberPropertyImpl<*, *> && name == other.name && owner == other.owner + + override fun hashCode(): Int = + name.hashCode() * 31 + owner.hashCode() } class KMutableMemberPropertyImpl( diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index 7e16b2479c0..a2bab0d6737 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -18,4 +18,10 @@ package kotlin.reflect.jvm.internal import kotlin.reflect.KPackage -class KPackageImpl(val jClass: Class<*>) : KPackage +class KPackageImpl(val jClass: Class<*>) : KPackage { + override fun equals(other: Any?): Boolean = + other is KPackageImpl && jClass == other.jClass + + override fun hashCode(): Int = + jClass.hashCode() +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt index 07b4ef66c4f..057a8cb5eba 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt @@ -32,6 +32,12 @@ open class KTopLevelExtensionPropertyImpl( override fun get(receiver: T): R { return getter(null, receiver) as R } + + override fun equals(other: Any?): Boolean = + other is KTopLevelExtensionPropertyImpl<*, *> && name == other.name && owner == other.owner && receiverClass == other.receiverClass + + override fun hashCode(): Int = + (name.hashCode() * 31 + owner.hashCode()) * 31 + receiverClass.hashCode() } class KMutableTopLevelExtensionPropertyImpl( diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt index ba15cb675f2..72dd86fa406 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt @@ -32,6 +32,12 @@ open class KTopLevelVariableImpl( override fun get(): R { return getter(null) as R } + + override fun equals(other: Any?): Boolean = + other is KTopLevelVariableImpl<*> && name == other.name && owner == other.owner + + override fun hashCode(): Int = + name.hashCode() * 31 + owner.hashCode() } class KMutableTopLevelVariableImpl( From bc8bce7ca1fe453fa87bf5543b4de468bc75b4a8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 1 Jul 2014 21:32:06 +0400 Subject: [PATCH 36/38] Provide "toString" for reflection objects --- .../methodsFromAny/classToString.kt | 14 ++++ .../methodsFromAny/defaultPackageToString.kt | 8 +++ .../extensionPropertyReceiverToString.kt | 66 +++++++++++++++++++ .../packageForJavaStaticToString.kt | 8 +++ .../methodsFromAny/packageToString.kt | 10 +++ .../methodsFromAny/propertyToString.kt | 26 ++++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 30 +++++++++ .../kotlin/reflect/jvm/internal/KClassImpl.kt | 3 + .../jvm/internal/KForeignMemberProperty.kt | 7 ++ .../jvm/internal/KMemberPropertyImpl.kt | 7 ++ .../reflect/jvm/internal/KPackageImpl.kt | 22 +++++++ .../KTopLevelExtensionPropertyImpl.kt | 40 +++++++++++ .../jvm/internal/KTopLevelVariableImpl.kt | 7 ++ 13 files changed, 248 insertions(+) create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/classToString.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/defaultPackageToString.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/extensionPropertyReceiverToString.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageForJavaStaticToString.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageToString.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/propertyToString.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/classToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/classToString.kt new file mode 100644 index 00000000000..6692de70e1f --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/classToString.kt @@ -0,0 +1,14 @@ +import kotlin.test.* +import kotlin.reflect.jvm.kotlin + +class A + +fun box(): String { + val p = javaClass().kotlin + if ("$p" != "class A") return "Fail: $p" + + val s = javaClass().kotlin + if ("$s" != "class java.lang.String") return "Fail: $s" + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/defaultPackageToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/defaultPackageToString.kt new file mode 100644 index 00000000000..cc711bc7d8d --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/defaultPackageToString.kt @@ -0,0 +1,8 @@ +import kotlin.test.* +import kotlin.reflect.jvm.kotlinPackage + +fun box(): String { + val p = Class.forName("_DefaultPackage").kotlinPackage + if ("$p" != "package ") return "Fail: $p" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/extensionPropertyReceiverToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/extensionPropertyReceiverToString.kt new file mode 100644 index 00000000000..2fc67171bc3 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/extensionPropertyReceiverToString.kt @@ -0,0 +1,66 @@ +import kotlin.reflect.KExtensionProperty +import kotlin.test.assertEquals + +fun check(expected: String, p: KExtensionProperty<*, *>) { + var s = p.toString() + // Strip "val" or "var" + s = s.substring(4) + // Strip property name, leave only receiver class + s = s.substring(0, s.lastIndexOf('.')) + + assertEquals(expected, s) +} + +val Boolean.x: Any get() = this +val Char.x: Any get() = this +val Byte.x: Any get() = this +val Short.x: Any get() = this +val Int.x: Any get() = this +val Float.x: Any get() = this +val Long.x: Any get() = this +val Double.x: Any get() = this + +val BooleanArray.x: Any get() = this +val CharArray.x: Any get() = this +val ByteArray.x: Any get() = this +val ShortArray.x: Any get() = this +val IntArray.x: Any get() = this +val FloatArray.x: Any get() = this +val LongArray.x: Any get() = this +val DoubleArray.x: Any get() = this + +val Array.a1: Any get() = this +val Array.a2: Any get() = this +val Array>.a3: Any get() = this +val Array.a4: Any get() = this + +val Map.m: Any get() = this + +fun box(): String { + check("kotlin.Boolean", Boolean::x) + check("kotlin.Char", Char::x) + check("kotlin.Byte", Byte::x) + check("kotlin.Short", Short::x) + check("kotlin.Int", Int::x) + check("kotlin.Float", Float::x) + check("kotlin.Long", Long::x) + check("kotlin.Double", Double::x) + + check("kotlin.BooleanArray", BooleanArray::x) + check("kotlin.CharArray", CharArray::x) + check("kotlin.ByteArray", ByteArray::x) + check("kotlin.ShortArray", ShortArray::x) + check("kotlin.IntArray", IntArray::x) + check("kotlin.FloatArray", FloatArray::x) + check("kotlin.LongArray", LongArray::x) + check("kotlin.DoubleArray", DoubleArray::x) + + check("kotlin.Array", Array::a1) + check("kotlin.Array", Array::a2) + check("kotlin.Array>", Array>::a3) + check("kotlin.Array", Array::a4) + + check("java.util.Map", Map::m) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageForJavaStaticToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageForJavaStaticToString.kt new file mode 100644 index 00000000000..2d015d38f17 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageForJavaStaticToString.kt @@ -0,0 +1,8 @@ +import kotlin.test.* +import kotlin.reflect.jvm.kotlinPackage + +fun box(): String { + val p = javaClass().kotlinPackage + if ("$p" != "package java.lang.String") return "Fail: $p" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageToString.kt new file mode 100644 index 00000000000..0f60b75b211 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageToString.kt @@ -0,0 +1,10 @@ +package test.foo.bar + +import kotlin.test.* +import kotlin.reflect.jvm.kotlinPackage + +fun box(): String { + val p = Class.forName("test.foo.bar.BarPackage").kotlinPackage + if ("$p" != "package test.foo.bar") return "Fail: $p" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/propertyToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/propertyToString.kt new file mode 100644 index 00000000000..2a1e96b7574 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/propertyToString.kt @@ -0,0 +1,26 @@ +package test + +import kotlin.test.assertEquals + +val top = 42 +var top2 = -23 + +val String.ext: Int get() = 0 +var IntRange?.ext2: Int get() = 0; set(value) {} + +class A(val mem: String) +class B(var mem: String) + +fun assertToString(s: String, x: Any) { + assertEquals(s, x.toString()) +} + +fun box(): String { + assertToString("val top", ::top) + assertToString("var top2", ::top2) + assertToString("val java.lang.String.ext", String::ext) + assertToString("var kotlin.IntRange.ext2", IntRange::ext2) + assertToString("val test.A.mem", A::mem) + assertToString("var test.B.mem", B::mem) + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 252025ee4ed..411dd47a771 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -1536,11 +1536,41 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("classToString.kt") + public void testClassToString() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/classToString.kt"); + } + + @TestMetadata("defaultPackageToString.kt") + public void testDefaultPackageToString() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/defaultPackageToString.kt"); + } + @TestMetadata("equalsHashCode.kt") public void testEqualsHashCode() throws Exception { doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/equalsHashCode.kt"); } + @TestMetadata("extensionPropertyReceiverToString.kt") + public void testExtensionPropertyReceiverToString() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/extensionPropertyReceiverToString.kt"); + } + + @TestMetadata("packageForJavaStaticToString.kt") + public void testPackageForJavaStaticToString() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageForJavaStaticToString.kt"); + } + + @TestMetadata("packageToString.kt") + public void testPackageToString() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/packageToString.kt"); + } + + @TestMetadata("propertyToString.kt") + public void testPropertyToString() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/propertyToString.kt"); + } + } public static Test innerSuite() { diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 49f66afefc7..fa339c7c336 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -62,4 +62,7 @@ class KClassImpl(val jClass: Class) : KClass { override fun hashCode(): Int = jClass.hashCode() + + override fun toString(): String = + jClass.toString() } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt index c0aab6889b1..ef62750475c 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt @@ -36,6 +36,10 @@ open class KForeignMemberProperty( override fun hashCode(): Int = name.hashCode() * 31 + owner.hashCode() + + // TODO: include visibility, return type + override fun toString(): String = + "val ${owner.jClass.getName()}.$name" } class KMutableForeignMemberProperty( @@ -47,4 +51,7 @@ class KMutableForeignMemberProperty( override fun set(receiver: T, value: R) { field.set(receiver, value) } + + override fun toString(): String = + "var ${owner.jClass.getName()}.$name" } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 8135c7dfea2..b6196ed9a50 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -45,6 +45,10 @@ open class KMemberPropertyImpl( override fun hashCode(): Int = name.hashCode() * 31 + owner.hashCode() + + // TODO: include visibility, return type + override fun toString(): String = + "val ${owner.jClass.getName()}.$name" } class KMutableMemberPropertyImpl( @@ -56,4 +60,7 @@ class KMutableMemberPropertyImpl( override fun set(receiver: T, value: R) { setter(receiver, value) } + + override fun toString(): String = + "var ${owner.jClass.getName()}.$name" } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index a2bab0d6737..4a5e182b304 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -17,6 +17,9 @@ package kotlin.reflect.jvm.internal import kotlin.reflect.KPackage +import kotlin.jvm.internal.KotlinPackage + +private val KOTLIN_PACKAGE_ANNOTATION_CLASS = javaClass() class KPackageImpl(val jClass: Class<*>) : KPackage { override fun equals(other: Any?): Boolean = @@ -24,4 +27,23 @@ class KPackageImpl(val jClass: Class<*>) : KPackage { override fun hashCode(): Int = jClass.hashCode() + + suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + override fun toString(): String { + val name = jClass.getName() as java.lang.String + return if (jClass.isAnnotationPresent(KOTLIN_PACKAGE_ANNOTATION_CLASS)) { + // Cast to Any is needed to suppress the error: "Operator '==' cannot be applied to 'java.lang.String' and 'kotlin.String'" + if ((name : Any) == "_DefaultPackage") { + "package " + } + else { + val lastDot = name.lastIndexOf(".") + if (lastDot >= 0) { + "package ${name.substring(0, lastDot)}" + } + else "package $name" + } + } + else "package $name" + } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt index 057a8cb5eba..d200c100f2e 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt @@ -38,6 +38,10 @@ open class KTopLevelExtensionPropertyImpl( override fun hashCode(): Int = (name.hashCode() * 31 + owner.hashCode()) * 31 + receiverClass.hashCode() + + // TODO: include visibility, return type, maybe package + override fun toString(): String = + "val ${mapJavaClassToKotlin(receiverClass.getName())}.$name" } class KMutableTopLevelExtensionPropertyImpl( @@ -50,4 +54,40 @@ class KMutableTopLevelExtensionPropertyImpl( override fun set(receiver: T, value: R) { setter.invoke(null, receiver, value) } + + override fun toString(): String = + "var ${mapJavaClassToKotlin(receiverClass.getName())}.$name" +} + +suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") +private fun mapJavaClassToKotlin(name: String): String { + if (Character.isLowerCase(name[0])) { + return when (name) { + "boolean" -> "kotlin.Boolean" + "char" -> "kotlin.Char" + "byte" -> "kotlin.Byte" + "short" -> "kotlin.Short" + "int" -> "kotlin.Int" + "float" -> "kotlin.Float" + "long" -> "kotlin.Long" + "double" -> "kotlin.Double" + else -> name + } + } + if (name[0] == '[') { + val element = (name as java.lang.String).substring(1) + return when (element[0]) { + 'Z' -> "kotlin.BooleanArray" + 'C' -> "kotlin.CharArray" + 'B' -> "kotlin.ByteArray" + 'S' -> "kotlin.ShortArray" + 'I' -> "kotlin.IntArray" + 'F' -> "kotlin.FloatArray" + 'J' -> "kotlin.LongArray" + 'D' -> "kotlin.DoubleArray" + 'L' -> "kotlin.Array<${mapJavaClassToKotlin((element as java.lang.String).substring(1, element.length() - 1))}>" + else -> "kotlin.Array<${mapJavaClassToKotlin(element)}>" + } + } + return name } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt index 72dd86fa406..d88bb73491e 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt @@ -38,6 +38,10 @@ open class KTopLevelVariableImpl( override fun hashCode(): Int = name.hashCode() * 31 + owner.hashCode() + + // TODO: include visibility, return type, maybe package + override fun toString(): String = + "val $name" } class KMutableTopLevelVariableImpl( @@ -49,4 +53,7 @@ class KMutableTopLevelVariableImpl( override fun set(value: R) { setter.invoke(null, value) } + + override fun toString(): String = + "var $name" } From a84d528325b4519a9ecd8265d5a2457d712abc51 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 1 Jul 2014 23:51:34 +0400 Subject: [PATCH 37/38] Improve performance of $kotlinClass field initializer Don't load annotations reflectively in each class' --- .../jet/codegen/ImplementationBodyCodegen.java | 2 +- .../src/kotlin/reflect/jvm/internal/KClassImpl.kt | 10 ++++++---- .../src/kotlin/reflect/jvm/internal/factory.kt | 5 ++++- .../src/kotlin/reflect/jvm/internal/foreignKClasses.kt | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 9425d6e31f1..2dc17723740 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -475,7 +475,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return; } - generateReflectionObjectField(state, classAsmType, v, method("kClass", K_CLASS_IMPL_TYPE, getType(Class.class)), + generateReflectionObjectField(state, classAsmType, v, method("kClassFromKotlin", K_CLASS_IMPL_TYPE, getType(Class.class)), JvmAbi.KOTLIN_CLASS_FIELD_NAME, createOrGetClInitCodegen().v); } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index fa339c7c336..9e8dee8842e 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -29,11 +29,13 @@ enum class KClassOrigin { private val KOTLIN_CLASS_ANNOTATION_CLASS = javaClass() private val KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS = javaClass() -class KClassImpl(val jClass: Class) : KClass { +class KClassImpl(val jClass: Class, isKnownToBeKotlin: Boolean) : KClass { // TODO: write metadata to local classes - val origin: KClassOrigin = - if (jClass.isAnnotationPresent(KOTLIN_CLASS_ANNOTATION_CLASS) || - jClass.isAnnotationPresent(KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS)) { + private val origin: KClassOrigin = + if (isKnownToBeKotlin || + jClass.isAnnotationPresent(KOTLIN_CLASS_ANNOTATION_CLASS) || + jClass.isAnnotationPresent(KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS) + ) { KClassOrigin.KOTLIN } else { diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt index 5fa0730bf36..86d5d7d5bcf 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt @@ -19,7 +19,10 @@ package kotlin.reflect.jvm.internal import kotlin.reflect.* fun kClass(jClass: Class): KClassImpl = - KClassImpl(jClass) + KClassImpl(jClass, false) + +fun kClassFromKotlin(jClass: Class): KClassImpl = + KClassImpl(jClass, true) fun kPackage(jClass: Class<*>): KPackageImpl = KPackageImpl(jClass) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt index adf795c49ce..acf8b1eb01b 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/foreignKClasses.kt @@ -53,13 +53,13 @@ fun foreignKotlinClass(jClass: Class): KClassImpl { val newArray = arrayOfNulls>>(size + 1) // Don't use Arrays.copyOf because it works reflectively System.arraycopy(cached, 0, newArray, 0, size) - val newKClass = KClassImpl(jClass) + val newKClass = kClass(jClass) newArray[size] = WeakReference(newKClass) FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray) return newKClass } - val newKClass = KClassImpl(jClass) + val newKClass = kClass(jClass) FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, WeakReference(newKClass)) return newKClass } From 36f7cc742f095f7dbb6b3a24f82c3b480fbabf6d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 2 Jul 2014 01:23:25 +0400 Subject: [PATCH 38/38] Introduce NoSuchPropertyException and IllegalAccessException No new tests added because it's difficult to model a situation where a ::-access is allowed but the code throws these exceptions at runtime --- .../property/privateClassVal.kt | 1 + .../property/privateClassVar.kt | 1 + .../property/protectedClassVar.kt | 1 + .../src/kotlin/reflect/exceptions.kt | 31 +++++++++++++++++++ .../jvm/internal/KForeignMemberProperty.kt | 21 +++++++++++-- .../jvm/internal/KMemberPropertyImpl.kt | 28 ++++++++++++++--- .../KTopLevelExtensionPropertyImpl.kt | 28 ++++++++++++++--- .../jvm/internal/KTopLevelVariableImpl.kt | 28 ++++++++++++++--- 8 files changed, 124 insertions(+), 15 deletions(-) create mode 100644 core/runtime.jvm/src/kotlin/reflect/exceptions.kt diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt index a762b05c1df..74399986a8f 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt @@ -1,3 +1,4 @@ +import kotlin.reflect.IllegalAccessException import kotlin.reflect.KMemberProperty import kotlin.reflect.jvm.accessible diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt index 19a42534cb0..42fde2a640f 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt @@ -1,3 +1,4 @@ +import kotlin.reflect.IllegalAccessException import kotlin.reflect.KMutableMemberProperty import kotlin.reflect.jvm.accessible diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt index 112038072a4..35237e8c153 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt @@ -1,3 +1,4 @@ +import kotlin.reflect.IllegalAccessException import kotlin.reflect.jvm.accessible class A(param: String) { diff --git a/core/runtime.jvm/src/kotlin/reflect/exceptions.kt b/core/runtime.jvm/src/kotlin/reflect/exceptions.kt new file mode 100644 index 00000000000..141196da129 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/exceptions.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect + +suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") +public class IllegalAccessException(cause: java.lang.IllegalAccessException) : Exception() { + { + (this as java.lang.Throwable).initCause(cause) + } +} + +suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") +public class NoSuchPropertyException(cause: Exception) : Exception() { + { + (this as java.lang.Throwable).initCause(cause) + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt index ef62750475c..50b0541b1d8 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt @@ -23,12 +23,22 @@ open class KForeignMemberProperty( public override val name: String, protected val owner: KClassImpl ) : KMemberProperty, KPropertyImpl { - override val field: Field = owner.jClass.getField(name) + override val field: Field = try { + owner.jClass.getField(name) + } + catch (e: NoSuchFieldException) { + throw NoSuchPropertyException(e) + } override val getter: Method? get() = null override fun get(receiver: T): R { - return field.get(receiver) as R + try { + return field.get(receiver) as R + } + catch (e: java.lang.IllegalAccessException) { + throw kotlin.reflect.IllegalAccessException(e) + } } override fun equals(other: Any?): Boolean = @@ -49,7 +59,12 @@ class KMutableForeignMemberProperty( override val setter: Method? get() = null override fun set(receiver: T, value: R) { - field.set(receiver, value) + try { + field.set(receiver, value) + } + catch (e: java.lang.IllegalAccessException) { + throw kotlin.reflect.IllegalAccessException(e) + } } override fun toString(): String = diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index b6196ed9a50..bd19fe400b2 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -34,10 +34,20 @@ open class KMemberPropertyImpl( } // TODO: extract, make lazy (weak?), use our descriptors knowledge - override val getter: Method = owner.jClass.getMaybeDeclaredMethod(getterName(name)) + override val getter: Method = try { + owner.jClass.getMaybeDeclaredMethod(getterName(name)) + } + catch (e: NoSuchMethodException) { + throw NoSuchPropertyException(e) + } override fun get(receiver: T): R { - return getter(receiver) as R + try { + return getter(receiver) as R + } + catch (e: java.lang.IllegalAccessException) { + throw kotlin.reflect.IllegalAccessException(e) + } } override fun equals(other: Any?): Boolean = @@ -55,10 +65,20 @@ class KMutableMemberPropertyImpl( name: String, owner: KClassImpl ) : KMutableMemberProperty, KMutablePropertyImpl, KMemberPropertyImpl(name, owner) { - override val setter: Method = owner.jClass.getMaybeDeclaredMethod(setterName(name), getter.getReturnType()!!) + override val setter: Method = try { + owner.jClass.getMaybeDeclaredMethod(setterName(name), getter.getReturnType()!!) + } + catch (e: NoSuchMethodException) { + throw NoSuchPropertyException(e) + } override fun set(receiver: T, value: R) { - setter(receiver, value) + try { + setter(receiver, value) + } + catch (e: java.lang.IllegalAccessException) { + throw kotlin.reflect.IllegalAccessException(e) + } } override fun toString(): String = diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt index d200c100f2e..e60ecc9ae20 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelExtensionPropertyImpl.kt @@ -27,10 +27,20 @@ open class KTopLevelExtensionPropertyImpl( override val field: Field? get() = null // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields - override val getter: Method = owner.jClass.getMethod(getterName(name), receiverClass) + override val getter: Method = try { + owner.jClass.getMethod(getterName(name), receiverClass) + } + catch (e: NoSuchMethodException) { + throw NoSuchPropertyException(e) + } override fun get(receiver: T): R { - return getter(null, receiver) as R + try { + return getter(null, receiver) as R + } + catch (e: java.lang.IllegalAccessException) { + throw kotlin.reflect.IllegalAccessException(e) + } } override fun equals(other: Any?): Boolean = @@ -49,10 +59,20 @@ class KMutableTopLevelExtensionPropertyImpl( owner: KPackageImpl, receiverClass: Class ) : KMutableTopLevelExtensionProperty, KMutablePropertyImpl, KTopLevelExtensionPropertyImpl(name, owner, receiverClass) { - override val setter: Method = owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!) + override val setter: Method = try { + owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!) + } + catch (e: NoSuchMethodException) { + throw NoSuchPropertyException(e) + } override fun set(receiver: T, value: R) { - setter.invoke(null, receiver, value) + try { + setter.invoke(null, receiver, value) + } + catch (e: java.lang.IllegalAccessException) { + throw kotlin.reflect.IllegalAccessException(e) + } } override fun toString(): String = diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt index d88bb73491e..8fa6a06609b 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt @@ -27,10 +27,20 @@ open class KTopLevelVariableImpl( override val field: Field? get() = null // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields - override val getter: Method = owner.jClass.getMethod(getterName(name)) + override val getter: Method = try { + owner.jClass.getMethod(getterName(name)) + } + catch (e: NoSuchMethodException) { + throw NoSuchPropertyException(e) + } override fun get(): R { - return getter(null) as R + try { + return getter(null) as R + } + catch (e: java.lang.IllegalAccessException) { + throw kotlin.reflect.IllegalAccessException(e) + } } override fun equals(other: Any?): Boolean = @@ -48,10 +58,20 @@ class KMutableTopLevelVariableImpl( name: String, owner: KPackageImpl ) : KMutableTopLevelVariable, KMutableVariableImpl, KTopLevelVariableImpl(name, owner) { - override val setter: Method = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) + override val setter: Method = try { + owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) + } + catch (e: NoSuchMethodException) { + throw NoSuchPropertyException(e) + } override fun set(value: R) { - setter.invoke(null, value) + try { + setter.invoke(null, value) + } + catch (e: java.lang.IllegalAccessException) { + throw kotlin.reflect.IllegalAccessException(e) + } } override fun toString(): String =