From d9ceda77430fd01c68fb117df92c908747e06961 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 20 Dec 2011 20:13:16 +0400 Subject: [PATCH] reading extension functions from binary classes --- .../jet/codegen/FunctionCodegen.java | 1 + .../resolve/java/JavaDescriptorResolver.java | 120 ++++++++++++++---- .../jet/lang/resolve/java/StdlibNames.java | 1 + compiler/testData/readClass/fun/ExtFun.kt | 3 + .../org/jetbrains/jet/ReadClassDataTest.java | 11 ++ .../src/jet/typeinfo/JetValueParameter.java | 5 + 6 files changed, 116 insertions(+), 25 deletions(-) create mode 100644 compiler/testData/readClass/fun/ExtFun.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 85eab7d6335..c8c9f3dee79 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -110,6 +110,7 @@ public class FunctionCodegen { if(receiverParameter.getType().isNullable()) { av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); } + av.visit(StdlibNames.JET_VALUE_PARAMETER_RECEIVER_FIELD, true); av.visitEnd(); } for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 14a934a3a16..6948e7ac5fe 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -9,6 +9,7 @@ import com.intellij.psi.*; import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope; import jet.typeinfo.TypeInfoVariance; +import org.eclipse.jdt.internal.core.JavaModelManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -214,7 +215,11 @@ public class JavaDescriptorResolver { classDescriptor, Collections.emptyList(), // TODO false); - constructorDescriptor.initialize(typeParameters, resolveParameterDescriptors(constructorDescriptor, constructor.getParameterList().getParameters()), Modality.FINAL, + ValueParameterDescriptors valueParameterDescriptors = resolveParameterDescriptors(constructorDescriptor, constructor.getParameterList().getParameters()); + if (valueParameterDescriptors.receiverType != null) { + throw new IllegalStateException(); + } + constructorDescriptor.initialize(typeParameters, valueParameterDescriptors.descriptors, Modality.FINAL, resolveVisibilityFromPsiModifiers(constructor)); constructorDescriptor.setReturnType(classDescriptor.getDefaultType()); classDescriptor.addConstructor(constructorDescriptor); @@ -522,21 +527,71 @@ public class JavaDescriptorResolver { semanticServices.getTrace().record(BindingContext.NAMESPACE, psiClass, namespaceDescriptor); return namespaceDescriptor; } + + private static class ValueParameterDescriptors { + private final JetType receiverType; + private final List descriptors; - public List resolveParameterDescriptors(DeclarationDescriptor containingDeclaration, PsiParameter[] parameters) { - List result = new ArrayList(); - for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) { - PsiParameter parameter = parameters[i]; - ValueParameterDescriptor valueParameterDescriptor = resolveParameterDescriptor(containingDeclaration, i, parameter); - if (valueParameterDescriptor != null) { - result.add(valueParameterDescriptor); - } + private ValueParameterDescriptors(@Nullable JetType receiverType, List descriptors) { + this.receiverType = receiverType; + this.descriptors = descriptors; } - return result; } - @Nullable - private ValueParameterDescriptor resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { + public ValueParameterDescriptors resolveParameterDescriptors(DeclarationDescriptor containingDeclaration, PsiParameter[] parameters) { + List result = new ArrayList(); + JetType receiverType = null; + for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) { + PsiParameter parameter = parameters[i]; + JvmMethodParameterMeaning meaning = resolveParameterDescriptor(containingDeclaration, i, parameter); + if (meaning.kind == JvmMethodParameterKind.TYPE_INFO) { + // TODO + } else if (meaning.kind == JvmMethodParameterKind.REGULAR) { + result.add(meaning.valueParameterDescriptor); + } else if (meaning.kind == JvmMethodParameterKind.RECEIVER) { + if (receiverType != null) { + throw new IllegalStateException("more then one receiver"); + } + receiverType = meaning.receiverType; + } + } + return new ValueParameterDescriptors(receiverType, result); + } + + private enum JvmMethodParameterKind { + REGULAR, + RECEIVER, + TYPE_INFO, + } + + private static class JvmMethodParameterMeaning { + private final JvmMethodParameterKind kind; + private final JetType receiverType; + private final ValueParameterDescriptor valueParameterDescriptor; + private final Object typeInfo; + + private JvmMethodParameterMeaning(JvmMethodParameterKind kind, JetType receiverType, ValueParameterDescriptor valueParameterDescriptor, Object typeInfo) { + this.kind = kind; + this.receiverType = receiverType; + this.valueParameterDescriptor = valueParameterDescriptor; + this.typeInfo = typeInfo; + } + + public static JvmMethodParameterMeaning receiver(@NotNull JetType receiverType) { + return new JvmMethodParameterMeaning(JvmMethodParameterKind.RECEIVER, receiverType, null, null); + } + + public static JvmMethodParameterMeaning regular(@NotNull ValueParameterDescriptor valueParameterDescriptor) { + return new JvmMethodParameterMeaning(JvmMethodParameterKind.REGULAR, null, valueParameterDescriptor, null); + } + + public static JvmMethodParameterMeaning typeInfo(@NotNull Object typeInfo) { + return new JvmMethodParameterMeaning(JvmMethodParameterKind.TYPE_INFO, null, null, typeInfo); + } + } + + @NotNull + private JvmMethodParameterMeaning resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { PsiType psiType = parameter.getType(); JetType varargElementType; @@ -552,6 +607,8 @@ public class JavaDescriptorResolver { boolean nullable = true; String typeFromAnnotation = null; + boolean receiver = false; + // TODO: must be very slow, make it lazy? String name = parameter.getName() != null ? parameter.getName() : "p" + i; for (PsiAnnotation annotation : parameter.getModifierList().getAnnotations()) { @@ -575,8 +632,16 @@ public class JavaDescriptorResolver { if (signatureExpression != null) { typeFromAnnotation = (String) signatureExpression.getValue(); } + + + PsiLiteralExpression receiverExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_RECEIVER_FIELD); + if (receiverExpression != null) { + receiver = true; + } + + } else if (annotation.getQualifiedName().equals(StdlibNames.JET_TYPE_PARAMETER.getFqName())) { - return null; + return JvmMethodParameterMeaning.typeInfo(new Object()); } } @@ -586,16 +651,20 @@ public class JavaDescriptorResolver { } else { outType = semanticServices.getTypeTransformer().transformToType(psiType); } - return new ValueParameterDescriptorImpl( - containingDeclaration, - i, - Collections.emptyList(), // TODO - name, - null, // TODO : review - changeNullable ? TypeUtils.makeNullableAsSpecified(outType, nullable) : outType, - false, - varargElementType - ); + if (receiver) { + return JvmMethodParameterMeaning.receiver(outType); + } else { + return JvmMethodParameterMeaning.regular(new ValueParameterDescriptorImpl( + containingDeclaration, + i, + Collections.emptyList(), // TODO + name, + null, // TODO : review + changeNullable ? TypeUtils.makeNullableAsSpecified(outType, nullable) : outType, + false, + varargElementType + )); + } } public VariableDescriptor resolveFieldToVariableDescriptor(DeclarationDescriptor containingDeclaration, PsiField field) { @@ -687,11 +756,12 @@ public class JavaDescriptorResolver { ); methodDescriptorCache.put(method, functionDescriptorImpl); List typeParameters = resolveMethodTypeParameters(method, functionDescriptorImpl); + ValueParameterDescriptors valueParameterDescriptors = resolveParameterDescriptors(functionDescriptorImpl, parameters); functionDescriptorImpl.initialize( - null, + valueParameterDescriptors.receiverType, DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor), typeParameters, - resolveParameterDescriptors(functionDescriptorImpl, parameters), + valueParameterDescriptors.descriptors, makeReturnType(returnType, method), Modality.convertFromFlags(method.hasModifierProperty(PsiModifier.ABSTRACT), !method.hasModifierProperty(PsiModifier.FINAL)), resolveVisibilityFromPsiModifiers(method) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java index dd071b38631..285ffe54b3c 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java @@ -13,6 +13,7 @@ public class StdlibNames { public static final String JET_VALUE_PARAMETER_HAS_DEFAULT_VALUE_FIELD = "hasDefaultValue"; public static final String JET_VALUE_PARAMETER_NULLABLE_FIELD = "nullable"; public static final String JET_VALUE_PARAMETER_TYPE_FIELD = "type"; + public static final String JET_VALUE_PARAMETER_RECEIVER_FIELD = "receiver"; public static final JvmClassName JET_TYPE_PARAMETER = new JvmClassName("jet.typeinfo.JetTypeParameter"); diff --git a/compiler/testData/readClass/fun/ExtFun.kt b/compiler/testData/readClass/fun/ExtFun.kt new file mode 100644 index 00000000000..f894ea8a631 --- /dev/null +++ b/compiler/testData/readClass/fun/ExtFun.kt @@ -0,0 +1,3 @@ +namespace test + +fun Int.shuffle() = 1 diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index 8960f3ccc53..04458738032 100644 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.Variance; @@ -226,6 +227,12 @@ public class ReadClassDataTest extends UsefulTestCase { serializeCommaSeparated(fun.getTypeParameters(), sb); sb.append(">"); } + + if (fun.getReceiverParameter().exists()) { + serialize(fun.getReceiverParameter(), sb); + sb.append("."); + } + sb.append(fun.getName()); sb.append("("); serializeCommaSeparated(fun.getValueParameters(), sb); @@ -233,6 +240,10 @@ public class ReadClassDataTest extends UsefulTestCase { serialize(fun.getReturnType(), sb); } + private void serialize(ExtensionReceiver extensionReceiver, StringBuilder sb) { + serialize(extensionReceiver.getType(), sb); + } + private void serialize(PropertyDescriptor prop, StringBuilder sb) { if (prop.isVar()) { sb.append("var "); diff --git a/stdlib/src/jet/typeinfo/JetValueParameter.java b/stdlib/src/jet/typeinfo/JetValueParameter.java index db0a4f52605..cc3b7aebbf0 100644 --- a/stdlib/src/jet/typeinfo/JetValueParameter.java +++ b/stdlib/src/jet/typeinfo/JetValueParameter.java @@ -35,6 +35,11 @@ public @interface JetValueParameter { */ boolean hasDefaultValue () default false; + /** + * @return if this parameter is receiver + */ + boolean receiver() default false; + /** * @return type unless Java type is correct Kotlin type. */