Conform functions to extension functions and vice versa
#KT-5989 Fixed
This commit is contained in:
@@ -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<FqNameUnsafe> functionClasses = computeIndexedFqNames("Function", FUNCTION_TRAIT_COUNT);
|
||||
public final Set<FqNameUnsafe> 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.<ValueParameterDescriptor, CompileTimeConstant<?>>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<FqNameUnsafe> 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;
|
||||
|
||||
+11
-1
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user