diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java index d647a08e795..e021f936e77 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java @@ -131,6 +131,14 @@ public class JvmRuntimeTypes { kFunctionClass.getMemberScope(typeArguments) ); - return Arrays.asList(functionImplType, kFunctionType); + //noinspection ConstantConditions + JetType functionType = getBuiltIns(descriptor).getFunctionType( + Annotations.EMPTY, + receiverType, + ExpressionTypingUtils.getValueParametersTypes(descriptor.getValueParameters()), + descriptor.getReturnType() + ); + + return Arrays.asList(functionImplType, kFunctionType, functionType); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java index 83a0617e85b..6b10d56d06b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -58,7 +58,6 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.Arrays; import java.util.ListIterator; import static kotlin.KotlinPackage.substringAfterLast; @@ -70,14 +69,11 @@ public class InlineCodegenUtil { public static final int API = Opcodes.ASM5; public static final String CAPTURED_FIELD_PREFIX = "$"; - public static final String THIS$0 = "this$0"; - public static final String RECEIVER$0 = "receiver$0"; - public static final String NON_LOCAL_RETURN = "$$$$$NON_LOCAL_RETURN$$$$$"; - public static final String FIRST_FUN_LABEL = "$$$$$ROOT$$$$$"; + public static final String NUMBERED_FUNCTION_PREFIX = "kotlin/jvm/functions/Function"; public static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"; public static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall"; public static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall"; @@ -251,20 +247,10 @@ public class InlineCodegenUtil { return getInlineName(codegenContext, currentDescriptor.getContainingDeclaration(), typeMapper) + "$" + suffix; } - public static boolean isInvokeOnLambda(String owner, String name) { - if (!OperatorConventions.INVOKE.asString().equals(name)) { - return false; - } - - for (String prefix : Arrays.asList("kotlin/jvm/functions/Function", "kotlin/ExtensionFunction")) { - if (owner.startsWith(prefix)) { - String suffix = owner.substring(prefix.length()); - if (isInteger(suffix)) { - return true; - } - } - } - return false; + public static boolean isInvokeOnLambda(@NotNull String owner, @NotNull String name) { + return OperatorConventions.INVOKE.asString().equals(name) && + owner.startsWith(NUMBERED_FUNCTION_PREFIX) && + isInteger(owner.substring(NUMBERED_FUNCTION_PREFIX.length())); } public static boolean isAnonymousConstructorCall(@NotNull String internalName, @NotNull String methodName) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt index 5ad59368ddc..ce0d4a0f67a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt @@ -16,16 +16,20 @@ package org.jetbrains.kotlin.resolve.calls.tasks.collectors +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.DescriptorUtils.isStaticNestedClass import org.jetbrains.kotlin.resolve.LibrarySourceHacks +import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassObjectType import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.expressions.OperatorConventions public trait CallableDescriptorCollector { @@ -48,8 +52,8 @@ public class CallableDescriptorCollectors(val collectors Iterable> { override fun iterator(): Iterator> = collectors.iterator() - [suppress("UNCHECKED_CAST")] companion - object { + @suppress("UNCHECKED_CAST") + companion object { public val FUNCTIONS_AND_VARIABLES: CallableDescriptorCollectors = CallableDescriptorCollectors(listOf( FUNCTIONS_COLLECTOR as CallableDescriptorCollector, @@ -73,7 +77,20 @@ private object FunctionCollector : CallableDescriptorCollector { val receiverScope = receiver.getMemberScope() - return receiverScope.getFunctions(name) + getConstructors(receiverScope, name, { !isStaticNestedClass(it) }) + val members = receiverScope.getFunctions(name) + val constructors = getConstructors(receiverScope, name, { !isStaticNestedClass(it) }) + + if (name == OperatorConventions.INVOKE && KotlinBuiltIns.isExtensionFunctionType(receiver)) { + // If we're looking for members of an extension function type, we ignore the non-extension "invoke"s + // that originate from the Function{n} class and only consider the synthesized "invoke" extensions. + // Otherwise confusing errors will be reported because the non-extension here beats the extension + // (because declarations beat synthesized members) + val (candidatesForReplacement, irrelevantInvokes) = + members.partition { it is FunctionInvokeDescriptor && it.getValueParameters().isNotEmpty() } + return createSynthesizedInvokes(candidatesForReplacement) + irrelevantInvokes + constructors + } + + return members + constructors } override fun getStaticMembersByName(receiver: JetType, name: Name, bindingTrace: BindingTrace): Collection { @@ -81,7 +98,15 @@ private object FunctionCollector : CallableDescriptorCollector { - return scope.getFunctions(name).filter { it.getExtensionReceiverParameter() != null } + val functions = scope.getFunctions(name) + val (extensions, nonExtensions) = functions.partition { it.getExtensionReceiverParameter() != null } + + if (name == OperatorConventions.INVOKE) { + // Create synthesized "invoke" extensions for each non-extension "invoke" found in the scope + return extensions + createSynthesizedInvokes(nonExtensions) + } + + return extensions } private fun getConstructors( @@ -180,4 +205,4 @@ private fun CallableDescriptorCollector.filtered(fil return delegate.toString() } } -} \ No newline at end of file +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt new file mode 100644 index 00000000000..467ca46916d --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tasks + +import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor +import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor.Kind.Function +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.TypeSubstitutor +import java.util.ArrayList + +fun createSynthesizedInvokes(functions: Collection): Collection { + val result = ArrayList(1) + + for (invoke in functions) { + if (invoke !is FunctionInvokeDescriptor || invoke.getValueParameters().isEmpty()) continue + + val synthesized = if ((invoke.getContainingDeclaration() as? FunctionClassDescriptor)?.functionKind == Function) { + createSynthesizedFunctionWithFirstParameterAsReceiver(invoke) + } + else { + val invokeDeclaration = invoke.getOverriddenDescriptors().single() + val synthesizedSuperFun = createSynthesizedFunctionWithFirstParameterAsReceiver(invokeDeclaration) + val fakeOverride = synthesizedSuperFun.copy( + invoke.getContainingDeclaration(), + synthesizedSuperFun.getModality(), + synthesizedSuperFun.getVisibility(), + CallableMemberDescriptor.Kind.FAKE_OVERRIDE, + true + ) + fakeOverride.addOverriddenDescriptor(synthesizedSuperFun) + fakeOverride + } + + result.add(synthesized.substitute(TypeSubstitutor.create(invoke.getDispatchReceiverParameter()!!.getType()))) + } + + return result +} + +private fun createSynthesizedFunctionWithFirstParameterAsReceiver(descriptor: FunctionDescriptor): FunctionDescriptor { + val result = SimpleFunctionDescriptorImpl.create( + descriptor.getContainingDeclaration(), + descriptor.getAnnotations(), + descriptor.getName(), + CallableMemberDescriptor.Kind.SYNTHESIZED, + descriptor.getSource() + ) + + val original = descriptor.getOriginal() + result.initialize( + original.getValueParameters().first().getType(), + original.getDispatchReceiverParameter(), + original.getTypeParameters(), + original.getValueParameters().drop(1).map { p -> + ValueParameterDescriptorImpl( + result, null, p.getIndex() - 1, p.getAnnotations(), Name.identifier("p${p.getIndex() + 1}"), p.getType(), + p.declaresDefaultValue(), p.getVarargElementType(), p.getSource() + ) + }, + original.getReturnType(), + original.getModality(), + original.getVisibility() + ) + + return result +} diff --git a/compiler/testData/codegen/box/functions/functionNtoString.kt b/compiler/testData/codegen/box/functions/functionNtoString.kt index fdd06bbbd18..2f5720b03d7 100644 --- a/compiler/testData/codegen/box/functions/functionNtoString.kt +++ b/compiler/testData/codegen/box/functions/functionNtoString.kt @@ -15,13 +15,13 @@ fun box(): String { check("kotlin.jvm.functions.Function2") { x: Int, y: Int -> } - check("kotlin.ExtensionFunction0", + check("kotlin.jvm.functions.Function1", fun Int.() {}) - check("kotlin.ExtensionFunction0", + check("kotlin.jvm.functions.Function1", fun Unit.(): Int = 42) - check("kotlin.ExtensionFunction1", + check("kotlin.jvm.functions.Function2", fun String.(s: String): Long = 42.toLong()) - check("kotlin.ExtensionFunction2", + check("kotlin.jvm.functions.Function3", fun Int.(x: Int, y: Int) {}) return "OK" diff --git a/compiler/testData/codegen/box/reflection/functionLiteralGenericSignature.kt b/compiler/testData/codegen/box/reflection/functionLiteralGenericSignature.kt index 60ee90aa2e6..58ea6580136 100644 --- a/compiler/testData/codegen/box/reflection/functionLiteralGenericSignature.kt +++ b/compiler/testData/codegen/box/reflection/functionLiteralGenericSignature.kt @@ -26,8 +26,8 @@ fun box(): String { assertGenericSuper("kotlin.jvm.functions.Function1, java.util.List>", mutableListFun) assertGenericSuper("kotlin.jvm.functions.Function1, kotlin.Unit>", funWithIn) - assertGenericSuper("kotlin.ExtensionFunction0", extensionFun) - assertGenericSuper("kotlin.ExtensionFunction1", extensionWithArgFun) + assertGenericSuper("kotlin.jvm.functions.Function1", extensionFun) + assertGenericSuper("kotlin.jvm.functions.Function2", extensionWithArgFun) return "OK" } diff --git a/compiler/testData/codegen/box/regressions/kt3999.kt b/compiler/testData/codegen/box/regressions/kt3999.kt index d6897d0fde5..4eac6a2e580 100644 --- a/compiler/testData/codegen/box/regressions/kt3999.kt +++ b/compiler/testData/codegen/box/regressions/kt3999.kt @@ -11,9 +11,9 @@ fun test1() { } fun test2() { - val a: ExtensionFunction1<*, *, *>.(ExtensionFunction1<*, *, *>)->Unit = {} - val b: ExtensionFunction1<*, *, *>.(ExtensionFunction1<*, *, *>)->Unit = {"$this $it"} - val c: ExtensionFunction1<*, *, *>.(ExtensionFunction1<*, *, *>)->Unit = {} + val a: (@extension Function2<*, *, *>).(@extension Function2<*, *, *>)->Unit = {} + val b: (@extension Function2<*, *, *>).(@extension Function2<*, *, *>)->Unit = {"$this $it"} + val c: (@extension Function2<*, *, *>).(@extension Function2<*, *, *>)->Unit = {} a.b(c) a b c } diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/function/toString.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/function/toString.kt deleted file mode 100644 index d341c0ec31c..00000000000 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/function/toString.kt +++ /dev/null @@ -1,23 +0,0 @@ -fun foo(s: String) {} - -class A { - fun bar(): String = "" -} - -fun A.baz(x: Int) {} - - -fun box(): String { - val f = "${::foo}" - if (f != "kotlin.reflect.KFunction1") return "Fail foo: $f" - - val nameOfA = (A() as java.lang.Object).getClass().getName() - - val g = "${A::bar}" - if (g != "kotlin.reflect.KMemberFunction0<$nameOfA, java.lang.String>") return "Fail bar: $g" - - val h = "${A::baz}" - if (h != "kotlin.reflect.KExtensionFunction1<$nameOfA, java.lang.Integer, kotlin.Unit>") return "Fail baz: $h" - - return "OK" -} diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/arrayAccess.kt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/arrayAccess.kt index 9db60d513ed..9af1f669a65 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/arrayAccess.kt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/arrayAccess.kt @@ -3,13 +3,8 @@ inline fun Function1.get(index : Int) { } -inline fun ExtensionFunction1.get(index : Int) { - -} - -inline fun inlineFunWithInvoke(s: (p: T) -> U, ext: T.(p: U) -> V) { +inline fun inlineFunWithInvoke(s: (p: T) -> U) { s[1] - ext[1] } //noinline @@ -17,11 +12,11 @@ fun Function2.get(index : Int) { } -fun ExtensionFunction2.get(index : Int) { +fun @extension Function3.get(index : Int) { } inline fun inlineFunWithInvoke(s: (p: T, l: U) -> V, ext: T.(p: U, l: V) -> W) { s[1] ext[1] -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/arrayAccess.txt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/arrayAccess.txt index cd3a400834b..6824c9c0a0e 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/arrayAccess.txt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/arrayAccess.txt @@ -1,8 +1,7 @@ -package +package -kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U, /*1*/ ext: T.(U) -> V): kotlin.Unit +kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U): kotlin.Unit kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T, U) -> V, /*1*/ ext: T.(U, V) -> W): kotlin.Unit kotlin.inline() internal fun ((T) -> U).get(/*0*/ index: kotlin.Int): kotlin.Unit internal fun ((T, U) -> V).get(/*0*/ index: kotlin.Int): kotlin.Unit -kotlin.inline() internal fun (T.(U) -> V).get(/*0*/ index: kotlin.Int): kotlin.Unit internal fun (T.(U, V) -> W).get(/*0*/ index: kotlin.Int): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/assignment.kt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/assignment.kt index 8ea305e5521..b3b183e71c0 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/assignment.kt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/assignment.kt @@ -12,14 +12,14 @@ inline fun Function1.plusAssign(p: Function1) { p -= this } -fun ExtensionFunction1.minusAssign(ext : ExtensionFunction1) {} +fun @extension Function2.minusAssign(ext : @extension Function2) {} -inline fun ExtensionFunction1.modAssign(ext : ExtensionFunction1) = { +inline fun @extension Function2.modAssign(ext : @extension Function2) = { this += ext ext += this } -inline fun ExtensionFunction1.plusAssign(ext : ExtensionFunction1) { +inline fun @extension Function2.plusAssign(ext : @extension Function2) { this -= ext ext -= this } @@ -27,4 +27,4 @@ inline fun ExtensionFunction1.plusAssign(ext : ExtensionFunct inline fun inlineFunWithInvoke(s: (p: T) -> U, ext: T.(p: U) -> V) { s += s ext += ext -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/comparison.kt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/comparison.kt index 66d35affdf8..c5832c2e0bf 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/comparison.kt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/comparison.kt @@ -1,23 +1,17 @@ // !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE inline fun Function1.compareTo(p: Function1) = 1 -inline fun ExtensionFunction1.compareTo(index : ExtensionFunction1) = 1 -inline fun inlineFunWithInvoke(s: (p: T) -> U, ext: T.(p: U) -> V) { +inline fun inlineFunWithInvoke(s: (p: T) -> U) { s < s s <= s s > s s >= s - - ext < ext - ext > ext - ext <= ext - ext >= ext } //noinline fun Function2.compareTo(index : Function2) = 1 -fun ExtensionFunction2.compareTo(index : ExtensionFunction2) = 1 +fun @extension Function3.compareTo(index : @extension Function3) = 1 inline fun inlineFunWithInvoke(s: (p: T, l: U) -> V, ext: T.(p: U, l: V) -> W) { s < s @@ -29,4 +23,4 @@ inline fun inlineFunWithInvoke(s: (p: T, l: U) -> V, ext: T.(p: U, ext > ext ext <= ext ext >= ext -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/comparison.txt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/comparison.txt index 1c5bdffb5ef..96091647329 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/comparison.txt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/comparison.txt @@ -1,8 +1,7 @@ -package +package -kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U, /*1*/ ext: T.(U) -> V): kotlin.Unit +kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U): kotlin.Unit kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T, U) -> V, /*1*/ ext: T.(U, V) -> W): kotlin.Unit kotlin.inline() internal fun ((T) -> U).compareTo(/*0*/ p: (T) -> U): kotlin.Int internal fun ((T, U) -> V).compareTo(/*0*/ index: (T, U) -> V): kotlin.Int -kotlin.inline() internal fun (T.(U) -> V).compareTo(/*0*/ index: T.(U) -> V): kotlin.Int internal fun (T.(U, V) -> W).compareTo(/*0*/ index: T.(U, V) -> W): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/componentAccess.kt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/componentAccess.kt index 6f1d8fb07ad..fd317924dbc 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/componentAccess.kt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/componentAccess.kt @@ -2,21 +2,17 @@ inline fun Function1.component1() = 1 inline fun Function1.component2() = 2 -inline fun ExtensionFunction1.component1() = 1 -inline fun ExtensionFunction1.component2() = 2 - -inline fun inlineFunWithInvoke(s: (p: T) -> U, ext: T.(p: U) -> V) { +inline fun inlineFunWithInvoke(s: (p: T) -> U) { val (d1, e1) = s - val (d2, e2) = ext } fun Function2.component1() = 1 fun Function2.component2() = 2 -fun ExtensionFunction2.component1() = 1 -fun ExtensionFunction2.component2() = 2 +fun @extension Function3.component1() = 1 +fun @extension Function3.component2() = 2 inline fun inlineFunWithInvoke(s: (p: T, l: U) -> V, ext: T.(p: U, l: V) -> W) { val (d1, e1) = s val (d2, e2) = ext -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/componentAccess.txt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/componentAccess.txt index 16d2badc80c..b8b8cba2fec 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/componentAccess.txt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/componentAccess.txt @@ -1,12 +1,10 @@ -package +package -kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U, /*1*/ ext: T.(U) -> V): kotlin.Unit +kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U): kotlin.Unit kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T, U) -> V, /*1*/ ext: T.(U, V) -> W): kotlin.Unit kotlin.inline() internal fun ((T) -> U).component1(): kotlin.Int internal fun ((T, U) -> V).component1(): kotlin.Int -kotlin.inline() internal fun (T.(U) -> V).component1(): kotlin.Int internal fun (T.(U, V) -> W).component1(): kotlin.Int kotlin.inline() internal fun ((T) -> U).component2(): kotlin.Int internal fun ((T, U) -> V).component2(): kotlin.Int -kotlin.inline() internal fun (T.(U) -> V).component2(): kotlin.Int internal fun (T.(U, V) -> W).component2(): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/contains.kt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/contains.kt index 4b23809b753..5bc22123a4f 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/contains.kt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/contains.kt @@ -5,25 +5,15 @@ inline fun Function1.contains(p: Function1): Boolean { return false } -inline fun ExtensionFunction1.contains(ext: ExtensionFunction1): Boolean { - ext in this - this in ext - return false -} - - -inline fun inlineFunWithInvoke(s: (p: T) -> U, ext: T.(p: U) -> V) { +inline fun inlineFunWithInvoke(s: (p: T) -> U) { s in s s !in s - - ext in ext - ext !in ext } fun Function2.contains(p: Function2): Boolean = false -fun ExtensionFunction2.contains(ext: ExtensionFunction2): Boolean = false +fun @extension Function3.contains(ext: @extension Function3): Boolean = false inline fun inlineFunWithInvoke(s: (p: T, l: U) -> U, ext: T.(p: U, l: U) -> V) { s in s @@ -31,4 +21,4 @@ inline fun inlineFunWithInvoke(s: (p: T, l: U) -> U, ext: T.(p: U, l: ext in ext ext !in ext -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/contains.txt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/contains.txt index b3f89bf2e78..c67e674cac5 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/contains.txt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/contains.txt @@ -1,8 +1,7 @@ -package +package -kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U, /*1*/ ext: T.(U) -> V): kotlin.Unit +kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U): kotlin.Unit kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T, U) -> U, /*1*/ ext: T.(U, U) -> V): kotlin.Unit kotlin.inline() internal fun ((T) -> U).contains(/*0*/ p: (T) -> U): kotlin.Boolean internal fun ((T, U) -> V).contains(/*0*/ p: (T, U) -> V): kotlin.Boolean -kotlin.inline() internal fun (T.(U) -> V).contains(/*0*/ ext: T.(U) -> V): kotlin.Boolean internal fun (T.(U, V) -> W).contains(/*0*/ ext: T.(U, V) -> W): kotlin.Boolean diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/mathOperations.kt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/mathOperations.kt index f5697775afc..729bf0f42c1 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/mathOperations.kt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/mathOperations.kt @@ -3,7 +3,7 @@ fun Function1.minus(p: Function1) { } -fun ExtensionFunction1.minus(p: T.(p: U) -> V) { +fun @extension Function2.minus(p: T.(p: U) -> V) { } @@ -11,7 +11,7 @@ inline fun Function1.plus(p: Function1) { this - p } -inline fun ExtensionFunction1.plus(p: T.(p: U) -> V) { +inline fun @extension Function2.plus(p: T.(p: U) -> V) { this - p } @@ -29,6 +29,6 @@ inline fun Function1.submit() { this + this } -inline fun ExtensionFunction1.submit() { +inline fun @extension Function2.submit() { this + this -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/rangeTo.kt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/rangeTo.kt index de45b3d7cdd..2a73c7a00db 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/rangeTo.kt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/rangeTo.kt @@ -6,19 +6,9 @@ inline fun Function1.rangeTo(p: Function1): Range { return 1..2 } -inline fun ExtensionFunction1.rangeTo(ext: ExtensionFunction1): Range { - ext..this - this..ext - return 1..2 -} - - -inline fun inlineFunWithInvoke(s: (p: T) -> U, ext: T.(p: U) -> V) { +inline fun inlineFunWithInvoke(s: (p: T) -> U) { s..s s..s - - ext..ext - ext..ext } @@ -26,7 +16,7 @@ fun Function2.rangeTo(p: Function2): Range { return 1..2 } -fun ExtensionFunction2.rangeTo(ext: ExtensionFunction2): Range { +fun @extension Function3.rangeTo(ext: @extension Function3): Range { return 1..2 } @@ -36,4 +26,4 @@ inline fun inlineFunWithInvoke(s: (p: T, l: U) -> U, ext: T.(p: U, l: ext..ext ext..ext -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/rangeTo.txt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/rangeTo.txt index 04e89a6625e..ff28cbe8e87 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/rangeTo.txt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/rangeTo.txt @@ -1,8 +1,7 @@ -package +package -kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U, /*1*/ ext: T.(U) -> V): kotlin.Unit +kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> U): kotlin.Unit kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T, U) -> U, /*1*/ ext: T.(U, U) -> V): kotlin.Unit kotlin.inline() internal fun ((T) -> U).rangeTo(/*0*/ p: (T) -> U): kotlin.Range internal fun ((T, U) -> V).rangeTo(/*0*/ p: (T, U) -> V): kotlin.Range -kotlin.inline() internal fun (T.(U) -> V).rangeTo(/*0*/ ext: T.(U) -> V): kotlin.Range internal fun (T.(U, V) -> W).rangeTo(/*0*/ ext: T.(U, V) -> W): kotlin.Range diff --git a/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.kt b/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.kt index 1416545562a..ddf78874b40 100644 --- a/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.kt +++ b/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.kt @@ -5,10 +5,10 @@ fun Function1.minus() = this inline fun Function1.inc() = this fun Function1.dec() = this -inline fun ExtensionFunction1.plus(){} -fun ExtensionFunction1.minus(){} -inline fun ExtensionFunction1.inc() = this -fun ExtensionFunction1.dec() = this +inline fun @extension Function2.plus(){} +fun @extension Function2.minus(){} +inline fun @extension Function2.inc() = this +fun @extension Function2.dec() = this inline fun inlineFunWithInvoke(s: (p: T) -> V, ext: T.(p: T) -> V) { +s @@ -32,4 +32,4 @@ inline fun Function1.inlineFunWithInvoke() { ++this this-- --this -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/unaryExpressions/notOperation.kt b/compiler/testData/diagnostics/tests/inline/unaryExpressions/notOperation.kt index 5585da9b664..805562fd1da 100644 --- a/compiler/testData/diagnostics/tests/inline/unaryExpressions/notOperation.kt +++ b/compiler/testData/diagnostics/tests/inline/unaryExpressions/notOperation.kt @@ -3,24 +3,19 @@ inline fun Function1.not() : Boolean { return !this } -inline fun ExtensionFunction1.not() : Boolean { - return !this -} - -inline fun inlineFunWithInvoke(s: (p: T) -> V, ext: T.(p: T) -> V) { +inline fun inlineFunWithInvoke(s: (p: T) -> V) { !s - !ext } fun Function2.not() : Boolean { return !this } -fun ExtensionFunction2.not() : Boolean { +fun @extension Function3.not() : Boolean { return !this } inline fun inlineFunWithInvoke(s: (p: T, l: U) -> V, ext: T.(p: T, l : U) -> V) { !s !ext -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inline/unaryExpressions/notOperation.txt b/compiler/testData/diagnostics/tests/inline/unaryExpressions/notOperation.txt index f6850f5b83f..c1c539c9129 100644 --- a/compiler/testData/diagnostics/tests/inline/unaryExpressions/notOperation.txt +++ b/compiler/testData/diagnostics/tests/inline/unaryExpressions/notOperation.txt @@ -1,8 +1,7 @@ -package +package -kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> V, /*1*/ ext: T.(T) -> V): kotlin.Unit +kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T) -> V): kotlin.Unit kotlin.inline() internal fun inlineFunWithInvoke(/*0*/ s: (T, U) -> V, /*1*/ ext: T.(T, U) -> V): kotlin.Unit kotlin.inline() internal fun ((T) -> V).not(): kotlin.Boolean internal fun ((T, U) -> V).not(): kotlin.Boolean -kotlin.inline() internal fun (T.(T) -> V).not(): kotlin.Boolean internal fun (T.(U, V) -> W).not(): kotlin.Boolean diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.kt b/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.kt index 6c303dd98c7..230a9ce53d4 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.kt @@ -5,7 +5,7 @@ fun test1(f: String.() -> Unit) { } fun test2(f: (Int) -> Int) { - 1.f(2) + 1.f(2) - 2.(f)(2) -} \ No newline at end of file + 2.(f)(2) +} diff --git a/compiler/testData/renderer/FunctionTypes.kt b/compiler/testData/renderer/FunctionTypes.kt index 98873c91813..631db4cbbcc 100644 --- a/compiler/testData/renderer/FunctionTypes.kt +++ b/compiler/testData/renderer/FunctionTypes.kt @@ -5,18 +5,18 @@ var v4: Function1 var v4: (() -> Int, (String) -> Unit) -> String var v5: Int.() -> Int var v6 : Int.(String, Int) -> Unit -var v7 : ExtensionFunction1 +var v7 : [extension] Function2 class F: Function0 var v8: F -class EF: ExtensionFunction0 +class EF: [extension] Function1 var v9: EF class GF: Function0 var v10: GF -class GEF: ExtensionFunction0 +class GEF: [extension] Function1 var v11: GEF //internal var v1: () -> kotlin.Unit defined in root package @@ -30,7 +30,7 @@ var v11: GEF //internal final class F : () -> kotlin.Unit defined in root package //public constructor F() defined in F //internal var v8: F defined in root package -//internal final class EF defined in root package +//internal final class EF : kotlin.String.() -> kotlin.Unit defined in root package //public constructor EF() defined in EF //internal var v9: EF defined in root package //internal final class GF : () -> T defined in root package diff --git a/compiler/testData/resolvedCalls/functionTypes/invokeForExtensionFunctionType.txt b/compiler/testData/resolvedCalls/functionTypes/invokeForExtensionFunctionType.txt index 670900139ee..0c8e537cbaa 100644 --- a/compiler/testData/resolvedCalls/functionTypes/invokeForExtensionFunctionType.txt +++ b/compiler/testData/resolvedCalls/functionTypes/invokeForExtensionFunctionType.txt @@ -5,8 +5,8 @@ fun bar(f: Int.()->Unit) { Resolved call: -Resulting descriptor: fun Int.invoke(): Unit defined in kotlin.ExtensionFunction0 +Resulting descriptor: fun Int.invoke(): Unit defined in kotlin.Function1 Explicit receiver kind = BOTH_RECEIVERS -Dispatch receiver = f {ExtensionFunction0} +Dispatch receiver = f {[kotlin.extension] Function1} Extension receiver = 1 {Int} diff --git a/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionTypeInvoke.txt b/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionTypeInvoke.txt index 8ed821533f3..251275e2c66 100644 --- a/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionTypeInvoke.txt +++ b/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionTypeInvoke.txt @@ -9,8 +9,8 @@ interface A { Resolved call: -Resulting descriptor: fun Int.invoke(): Unit defined in kotlin.ExtensionFunction0 +Resulting descriptor: fun Int.invoke(): Unit defined in kotlin.Function1 Explicit receiver kind = BOTH_RECEIVERS -Dispatch receiver = foo {ExtensionFunction0} +Dispatch receiver = foo {[kotlin.extension] Function1} Extension receiver = 1 {Int} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index b8144eae990..25b4c9fc486 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -561,12 +561,6 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } - @TestMetadata("toString.kt") - public void testToString() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/function/toString.kt"); - doTestWithStdlib(fileName); - } - @TestMetadata("topLevelFromClass.kt") public void testTopLevelFromClass() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/function/topLevelFromClass.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 8368dd3fd3c..585a678e25a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -24,13 +24,16 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl; import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl; import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.scopes.JetScope; import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.types.*; @@ -39,8 +42,7 @@ import org.jetbrains.kotlin.types.checker.JetTypeChecker; import java.io.InputStream; import java.util.*; -import static kotlin.KotlinPackage.setOf; -import static kotlin.KotlinPackage.single; +import static kotlin.KotlinPackage.*; import static org.jetbrains.kotlin.builtins.PrimitiveType.*; import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName; @@ -178,6 +180,7 @@ public class KotlinBuiltIns { public final FqName inline = fqName("inline"); public final FqName noinline = fqName("noinline"); public final FqName inlineOptions = fqName("inlineOptions"); + public final FqName extension = fqName("extension"); public final FqNameUnsafe kClass = new FqName("kotlin.reflect.KClass").toUnsafe(); @@ -193,7 +196,6 @@ public class KotlinBuiltIns { } public final Set functionClasses = computeIndexedFqNames("Function", FUNCTION_TRAIT_COUNT); - public final Set extensionFunctionClasses = computeIndexedFqNames("ExtensionFunction", FUNCTION_TRAIT_COUNT); @NotNull private static FqNameUnsafe fqNameUnsafe(@NotNull String simpleName) { @@ -346,9 +348,14 @@ public class KotlinBuiltIns { return getBuiltInClassByName("Function" + parameterCount); } + /** + * @return the descriptor representing the class kotlin.Function{parameterCount + 1} + * @deprecated there are no ExtensionFunction classes anymore, use {@link #getFunction(int)} instead + */ + @Deprecated @NotNull public ClassDescriptor getExtensionFunction(int parameterCount) { - return getBuiltInClassByName("ExtensionFunction" + parameterCount); + return getBuiltInClassByName("Function" + (parameterCount + 1)); } @NotNull @@ -650,6 +657,16 @@ public class KotlinBuiltIns { return getBuiltInClassByName("PropertyMetadataImpl"); } + @NotNull + public AnnotationDescriptor createExtensionAnnotation() { + return new AnnotationDescriptorImpl(getBuiltInClassByName("extension").getDefaultType(), + Collections.>emptyMap()); + } + + private static boolean isTypeAnnotatedWithExtension(@NotNull JetType type) { + return type.getAnnotations().findAnnotation(FQ_NAMES.extension) != null; + } + @NotNull public JetType getFunctionType( @NotNull Annotations annotations, @@ -662,7 +679,17 @@ public class KotlinBuiltIns { ClassDescriptor classDescriptor = receiverType == null ? getFunction(size) : getExtensionFunction(size); TypeConstructor constructor = classDescriptor.getTypeConstructor(); - return new JetTypeImpl(annotations, constructor, false, arguments, classDescriptor.getMemberScope(arguments)); + Annotations typeAnnotations = receiverType == null ? annotations : addExtensionAnnotation(annotations); + + return new JetTypeImpl(typeAnnotations, constructor, false, arguments, classDescriptor.getMemberScope(arguments)); + } + + @NotNull + private Annotations addExtensionAnnotation(@NotNull Annotations annotations) { + if (annotations.findAnnotation(FQ_NAMES.extension) != null) return annotations; + + // TODO: preserve laziness of given annotations + return new AnnotationsImpl(plus(annotations, listOf(createExtensionAnnotation()))); } @NotNull @@ -741,21 +768,20 @@ public class KotlinBuiltIns { } public static boolean isExactFunctionType(@NotNull JetType type) { - return isTypeConstructorFqNameInSet(type, FQ_NAMES.functionClasses); + return isTypeConstructorFqNameInSet(type, FQ_NAMES.functionClasses) && !isTypeAnnotatedWithExtension(type); } public static boolean isExactExtensionFunctionType(@NotNull JetType type) { - return isTypeConstructorFqNameInSet(type, FQ_NAMES.extensionFunctionClasses); + return isTypeConstructorFqNameInSet(type, FQ_NAMES.functionClasses) && isTypeAnnotatedWithExtension(type); } - public static boolean isExactFunctionType(@NotNull FqNameUnsafe fqName) { + /** + * @return true if this is an FQ name of a fictitious class representing the function type, e.g. kotlin.Function1 + */ + public static boolean isNumberedFunctionClassFqName(@NotNull FqNameUnsafe fqName) { return FQ_NAMES.functionClasses.contains(fqName); } - public static boolean isExactExtensionFunctionType(@NotNull FqNameUnsafe fqName) { - return FQ_NAMES.extensionFunctionClasses.contains(fqName); - } - private static boolean isTypeConstructorFqNameInSet(@NotNull JetType type, @NotNull Set classes) { ClassifierDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); @@ -769,6 +795,7 @@ public class KotlinBuiltIns { public static JetType getReceiverType(@NotNull JetType type) { assert isFunctionOrExtensionFunctionType(type) : type; if (isExtensionFunctionType(type)) { + // TODO: this is incorrect when a class extends from an extension function and swaps type arguments return type.getArguments().get(0).getType(); } return null; diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionClassDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionClassDescriptor.kt index 9161f5aac8a..eda7fd1725c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionClassDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionClassDescriptor.kt @@ -16,10 +16,12 @@ package org.jetbrains.kotlin.builtins.functions +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor.Kind import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl import org.jetbrains.kotlin.descriptors.impl.AbstractClassDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl import org.jetbrains.kotlin.name.Name @@ -140,7 +142,15 @@ public class FunctionClassDescriptor( val module = containingDeclaration.getContainingDeclaration() val kotlinPackageFragment = module.getPackage(BUILT_INS_PACKAGE_FQ_NAME)!!.getFragments().single() - add(kotlinPackageFragment, Kind.Function.numberedClassName(functionArity), Annotations.EMPTY) + + // If this is a KMemberFunction{n} or KExtensionFunction{n}, it extends Function{n} with the annotation kotlin.extension, + // so that the value of this type is callable as an extension function, with the receiver before the dot + val annotations = + if (functionKind.hasDispatchReceiver || functionKind.hasExtensionReceiver) + AnnotationsImpl(listOf(KotlinBuiltIns.getInstance().createExtensionAnnotation())) + else Annotations.EMPTY + + add(kotlinPackageFragment, Kind.Function.numberedClassName(functionArity), annotations) } result.toReadOnlyList() diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClassClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClassClsStubBuilder.kt index c24db528d13..a4b20654904 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClassClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClassClsStubBuilder.kt @@ -25,7 +25,9 @@ import org.jetbrains.kotlin.idea.decompiler.stubBuilder.FlagsToModifiers.VISIBIL import org.jetbrains.kotlin.lexer.JetModifierKeywordToken import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.JetClassBody +import org.jetbrains.kotlin.psi.JetDelegationSpecifierList +import org.jetbrains.kotlin.psi.JetDelegatorToSuperClass import org.jetbrains.kotlin.psi.stubs.elements.JetClassElementType import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes import org.jetbrains.kotlin.psi.stubs.impl.KotlinClassStubImpl @@ -103,11 +105,10 @@ private class ClassClsStubBuilder( val isCompanionObject = classKind == ProtoBuf.Class.Kind.CLASS_OBJECT val fqName = outerContext.containerFqName.child(classId.getShortClassName()) val shortName = fqName.shortName().ref() - val superTypeRefs = supertypeIds.filter { + val superTypeRefs = supertypeIds.filterNot { //TODO: filtering function types should go away - !KotlinBuiltIns.isExactFunctionType(it.asSingleFqName().toUnsafe()) && - !KotlinBuiltIns.isExactExtensionFunctionType(it.asSingleFqName().toUnsafe()) - }.map { it.getShortClassName().ref() }.copyToArray() + KotlinBuiltIns.isNumberedFunctionClassFqName(it.asSingleFqName().toUnsafe()) + }.map { it.getShortClassName().ref() }.toTypedArray() return when (classKind) { ProtoBuf.Class.Kind.OBJECT, ProtoBuf.Class.Kind.CLASS_OBJECT -> { KotlinObjectStubImpl( @@ -184,7 +185,7 @@ private class ClassClsStubBuilder( classBody, qualifiedName = c.containerFqName.child(name).ref(), name = name.ref(), - superNames = array(), + superNames = arrayOf(), isTrait = false, isEnumEntry = true, isLocal = false, diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt index 61b9d97868c..52ef91dbce8 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt @@ -42,35 +42,31 @@ import java.util.ArrayList class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { - fun createTypeReferenceStub(parent: StubElement, typeProto: Type) { + fun createTypeReferenceStub(parent: StubElement, type: Type) { val typeReference = KotlinPlaceHolderStubImpl(parent, JetStubElementTypes.TYPE_REFERENCE) - val typeAnnotations = c.components.annotationLoader.loadTypeAnnotations(typeProto, c.nameResolver).filterNot { + val annotations = c.components.annotationLoader.loadTypeAnnotations(type, c.nameResolver).filterNot { val isTopLevelClass = !it.isNestedClass() isTopLevelClass && it.asSingleFqName() in JvmAnnotationNames.ANNOTATIONS_COPIED_TO_TYPES } - if (typeAnnotations.isNotEmpty()) { - createAnnotationStubs(typeAnnotations, typeReference, needWrappingAnnotationEntries = true) - } - createTypeStub(typeReference, typeProto) - } + val effectiveParent = + if (type.getNullable()) KotlinPlaceHolderStubImpl(typeReference, JetStubElementTypes.NULLABLE_TYPE) + else typeReference - private fun createTypeStub(parent: StubElement, type: Type) { - val isNullable = type.getNullable() - val effectiveParent = if (isNullable) KotlinPlaceHolderStubImpl(parent, JetStubElementTypes.NULLABLE_TYPE) else parent when (type.getConstructor().getKind()) { Type.Constructor.Kind.CLASS -> { - createClassReferenceTypeStub(effectiveParent, type) + createClassReferenceTypeStub(effectiveParent, type, annotations) } Type.Constructor.Kind.TYPE_PARAMETER -> { + createTypeAnnotationStubs(effectiveParent, annotations) val typeParameterName = c.typeParameters[type.getConstructor().getId()] createStubForTypeName(ClassId.topLevel(FqName.topLevel(typeParameterName)), effectiveParent) } } } - private fun createClassReferenceTypeStub(parent: StubElement, type: Type) { + private fun createClassReferenceTypeStub(parent: KotlinStubBaseImpl<*>, type: Type, annotations: List) { if (type.hasFlexibleTypeCapabilitiesId()) { val id = c.nameResolver.getString(type.getFlexibleTypeCapabilitiesId()) @@ -81,17 +77,19 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { } val classId = c.nameResolver.getClassId(type.getConstructor().getId()) - val fqName = classId.asSingleFqName().toUnsafe() - val isFunctionType = KotlinBuiltIns.isExactFunctionType(fqName) - val isExtensionFunctionType = KotlinBuiltIns.isExactExtensionFunctionType(fqName) - if (isFunctionType || isExtensionFunctionType) { - createFunctionTypeStub(parent, type, isExtensionFunctionType) + if (KotlinBuiltIns.isNumberedFunctionClassFqName(classId.asSingleFqName().toUnsafe())) { + val extension = annotations.any { annotation -> annotation.asSingleFqName() == KotlinBuiltIns.FQ_NAMES.extension } + createFunctionTypeStub(parent, type, extension) return } + createTypeAnnotationStubs(parent, annotations) val typeStub = createStubForTypeName(classId, parent) val typeArgumentProtoList = type.getArgumentList() createTypeArgumentListStub(typeStub, typeArgumentProtoList) - return + } + + private fun createTypeAnnotationStubs(parent: KotlinStubBaseImpl<*>, annotations: List) { + createAnnotationStubs(annotations, parent, needWrappingAnnotationEntries = true) } private fun createTypeArgumentListStub(typeStub: KotlinUserTypeStub, typeArgumentProtoList: List) { @@ -129,7 +127,7 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { val parameterList = KotlinPlaceHolderStubImpl(functionType, JetStubElementTypes.VALUE_PARAMETER_LIST) val typeArgumentsWithoutReceiverAndReturnType - = typeArgumentList.subList(if (isExtensionFunctionType) 1 else 0, typeArgumentList.size - 1) + = typeArgumentList.subList(if (isExtensionFunctionType) 1 else 0, typeArgumentList.size() - 1) typeArgumentsWithoutReceiverAndReturnType.forEach { argument -> val parameter = KotlinParameterStubImpl(parameterList, fqName = null, name = null, isMutable = false, hasValOrVarNode = false, hasDefaultValue = false) createTypeReferenceStub(parameter, argument.getType()) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/IndexUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/IndexUtils.kt index 5dae1ea19c2..c9b41db7b80 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/IndexUtils.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/IndexUtils.kt @@ -62,8 +62,8 @@ private fun JetTypeElement.index(declarat is JetNullableType -> getInnerType()?.index(declaration, sink) is JetFunctionType -> { - val typeName = (if (getReceiverTypeReference() != null) "ExtensionFunction" else "Function") + getParameters().size() - occurrence(typeName) + val arity = getParameters().size() + (if (getReceiverTypeReference() != null) 1 else 0) + occurrence("Function$arity") } is JetDynamicType -> occurrence("Any") diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction2/NotImportedExtensionFunction2.dependency.kt b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction2/NotImportedExtensionFunction2.dependency.kt index daad50bf546..a6cb72ea336 100644 --- a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction2/NotImportedExtensionFunction2.dependency.kt +++ b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction2/NotImportedExtensionFunction2.dependency.kt @@ -6,11 +6,11 @@ fun (() -> Unit)?.helloFun1() { fun Function0.helloFun2() { } -fun ExtensionFunction0.helloFun3() { +fun @extension Function1.helloFun3() { } fun Function1.helloFun4() { } fun Any.helloAny() { -} \ No newline at end of file +} diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction3/NotImportedExtensionFunction3.dependency.kt b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction3/NotImportedExtensionFunction3.dependency.kt index eea4d0f70d8..450acef59e4 100644 --- a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction3/NotImportedExtensionFunction3.dependency.kt +++ b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction3/NotImportedExtensionFunction3.dependency.kt @@ -6,14 +6,14 @@ fun (String.() -> Unit)?.helloFun1() { fun Function0.helloFun2() { } -fun ExtensionFunction0.helloFun3() { +fun @extension Function1.helloFun3() { } -fun ExtensionFunction0.helloFun4() { +fun @extension Function1.helloFun4() { } fun Function1.helloFun5() { } fun Any.helloAny() { -} \ No newline at end of file +} diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction3/NotImportedExtensionFunction3.kt b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction3/NotImportedExtensionFunction3.kt index d04ab3f1f94..5672d605215 100644 --- a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction3/NotImportedExtensionFunction3.kt +++ b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionFunction3/NotImportedExtensionFunction3.kt @@ -8,6 +8,6 @@ fun firstFun(p: String.() -> Unit) { // ABSENT: helloFun2 // EXIST: helloFun3 // ABSENT: helloFun4 -// ABSENT: helloFun5 +// EXIST: helloFun5 // EXIST: helloAny // NOTHING_ELSE: true diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/FrameVisitor.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/FrameVisitor.kt index bd89ba77e13..607685938cc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/FrameVisitor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/FrameVisitor.kt @@ -26,6 +26,7 @@ import org.jetbrains.eval4j.jdi.asJdiValue import org.jetbrains.eval4j.jdi.asValue import org.jetbrains.eval4j.obj import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.AsmTypes @@ -99,8 +100,8 @@ class FrameVisitor(context: EvaluationContextImpl) { } private fun isFunctionType(type: Type?): Boolean { - if (type == null || AsmUtil.isPrimitive(type)) return false - return type.getInternalName().startsWith("kotlin/Function") || type.getInternalName().startsWith("kotlin/ExtensionFunction") + return type?.getSort() == Type.OBJECT && + type!!.getInternalName().startsWith(InlineCodegenUtil.NUMBERED_FUNCTION_PREFIX) } private fun findLocalVariable(name: String, asmType: Type?, checkType: Boolean): Value? { diff --git a/idea/testData/unifier/equivalence/types/function0.kt b/idea/testData/unifier/equivalence/types/function0.kt index 2abc4a87d17..adc2e0288c7 100644 --- a/idea/testData/unifier/equivalence/types/function0.kt +++ b/idea/testData/unifier/equivalence/types/function0.kt @@ -4,4 +4,4 @@ val c: () -> String = { "" } val d: () -> kotlin.String = { "" } val e: () -> Unit = { } val f: Any.() -> String = { "" } -val g: ExtensionFunction0 = { "" } \ No newline at end of file +val g: @extension Function1 = { "" } diff --git a/idea/testData/unifier/equivalence/types/function1.kt b/idea/testData/unifier/equivalence/types/function1.kt index 8304a146185..eb07cab248c 100644 --- a/idea/testData/unifier/equivalence/types/function1.kt +++ b/idea/testData/unifier/equivalence/types/function1.kt @@ -5,6 +5,6 @@ val d: (n: Int) -> kotlin.String = { "" } val e: (String) -> Int = { 0 } val f: () -> Int = { 0 } val g: Int.() -> String = { "" } -val h: ExtensionFunction1 = { "" } +val h: @extension Function2 = { "" } val i: (m: Int) -> kotlin.String = { "" } -val j: ExtensionFunction0 = { "" } \ No newline at end of file +val j: @extension Function1 = { "" } diff --git a/idea/testData/unifier/equivalence/types/function1.kt.match b/idea/testData/unifier/equivalence/types/function1.kt.match index f1d28f35014..50dc32be4c4 100644 --- a/idea/testData/unifier/equivalence/types/function1.kt.match +++ b/idea/testData/unifier/equivalence/types/function1.kt.match @@ -6,4 +6,8 @@ kotlin.Function1 (n: Int) -> kotlin.String -(m: Int) -> kotlin.String \ No newline at end of file +Int.() -> String + +(m: Int) -> kotlin.String + +@extension Function1 diff --git a/idea/testData/unifier/equivalence/types/function2.kt b/idea/testData/unifier/equivalence/types/function2.kt index 78250768f61..7e98a01c251 100644 --- a/idea/testData/unifier/equivalence/types/function2.kt +++ b/idea/testData/unifier/equivalence/types/function2.kt @@ -6,6 +6,6 @@ val e: (String) -> Int = { 0 } val f: () -> Int = { 0 } val g: Any.(Int) -> String = { "" } val h: Int.(Any) -> String = { "" } -val i: ExtensionFunction2 = { a, b -> "" } +val i: @extension Function3 = { a, b -> "" } val j: (t: Any, u: Int) -> kotlin.String = { a, b -> "" } -val k: ExtensionFunction1 = { "" } \ No newline at end of file +val k: @extension Function2 = { "" } diff --git a/idea/testData/unifier/equivalence/types/function2.kt.match b/idea/testData/unifier/equivalence/types/function2.kt.match index 9eee15c239e..f3d72847299 100644 --- a/idea/testData/unifier/equivalence/types/function2.kt.match +++ b/idea/testData/unifier/equivalence/types/function2.kt.match @@ -6,4 +6,8 @@ kotlin.Function2 (a: Any, n: Int) -> kotlin.String -(t: Any, u: Int) -> kotlin.String \ No newline at end of file +Any.(Int) -> String + +(t: Any, u: Int) -> kotlin.String + +@extension Function2 diff --git a/js/js.translator/testData/expression/invoke/cases/infixCall.kt b/js/js.translator/testData/expression/invoke/cases/infixCall.kt index 00b88536463..b83f9225ff8 100644 --- a/js/js.translator/testData/expression/invoke/cases/infixCall.kt +++ b/js/js.translator/testData/expression/invoke/cases/infixCall.kt @@ -15,13 +15,13 @@ fun test1(): String { } fun test2(): String { - val a: ExtensionFunction1<*, *, *>.(ExtensionFunction1<*, *, *>)->String = { "a" } - val b: ExtensionFunction1<*, *, *>.(ExtensionFunction1<*, *, *>)->String = { - val aa = this as ExtensionFunction1; - val cc = it as ExtensionFunction1; + val a: (@extension Function2<*, *, *>).(@extension Function2<*, *, *>)->String = { "a" } + val b: (@extension Function2<*, *, *>).(@extension Function2<*, *, *>)->String = { + val aa = this as @extension Function2; + val cc = it as @extension Function2; "${null.aa(null)} b ${null.cc(null)}" } - val c: ExtensionFunction1<*, *, *>.(ExtensionFunction1<*, *, *>)->String = { "c" } + val c: (@extension Function2<*, *, *>).(@extension Function2<*, *, *>)->String = { "c" } val f = a.b(c) // works val s = a b c //compiler crashes diff --git a/libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt b/libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt index 1b7468509aa..7d22fb428fa 100644 --- a/libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt +++ b/libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt @@ -134,7 +134,7 @@ abstract class KDocTemplate() : TextTemplate() { return if (c != null) { val prefix = if (c.isAnnotation()) "@" else "" val cname = c.name - if ((cname.startsWith("kotlin.Function") || cname.startsWith("kotlin.ExtensionFunction")) && arguments.isNotEmpty()) { + if (cname.startsWith("kotlin.Function") && arguments.isNotEmpty()) { val rt = arguments.last() // TODO use drop() val rest = arguments.subList(0, arguments.size - 1).orEmpty()