reading extension functions from binary classes

This commit is contained in:
Stepan Koltsov
2011-12-20 20:13:16 +04:00
parent b48d4b4ab1
commit d9ceda7743
6 changed files with 116 additions and 25 deletions
@@ -110,6 +110,7 @@ public class FunctionCodegen {
if(receiverParameter.getType().isNullable()) { if(receiverParameter.getType().isNullable()) {
av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true);
} }
av.visit(StdlibNames.JET_VALUE_PARAMETER_RECEIVER_FIELD, true);
av.visitEnd(); av.visitEnd();
} }
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
@@ -9,6 +9,7 @@ import com.intellij.psi.*;
import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.DelegatingGlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope;
import jet.typeinfo.TypeInfoVariance; import jet.typeinfo.TypeInfoVariance;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
@@ -214,7 +215,11 @@ public class JavaDescriptorResolver {
classDescriptor, classDescriptor,
Collections.<AnnotationDescriptor>emptyList(), // TODO Collections.<AnnotationDescriptor>emptyList(), // TODO
false); 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)); resolveVisibilityFromPsiModifiers(constructor));
constructorDescriptor.setReturnType(classDescriptor.getDefaultType()); constructorDescriptor.setReturnType(classDescriptor.getDefaultType());
classDescriptor.addConstructor(constructorDescriptor); classDescriptor.addConstructor(constructorDescriptor);
@@ -522,21 +527,71 @@ public class JavaDescriptorResolver {
semanticServices.getTrace().record(BindingContext.NAMESPACE, psiClass, namespaceDescriptor); semanticServices.getTrace().record(BindingContext.NAMESPACE, psiClass, namespaceDescriptor);
return namespaceDescriptor; return namespaceDescriptor;
} }
private static class ValueParameterDescriptors {
private final JetType receiverType;
private final List<ValueParameterDescriptor> descriptors;
public List<ValueParameterDescriptor> resolveParameterDescriptors(DeclarationDescriptor containingDeclaration, PsiParameter[] parameters) { private ValueParameterDescriptors(@Nullable JetType receiverType, List<ValueParameterDescriptor> descriptors) {
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>(); this.receiverType = receiverType;
for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) { this.descriptors = descriptors;
PsiParameter parameter = parameters[i];
ValueParameterDescriptor valueParameterDescriptor = resolveParameterDescriptor(containingDeclaration, i, parameter);
if (valueParameterDescriptor != null) {
result.add(valueParameterDescriptor);
}
} }
return result;
} }
@Nullable public ValueParameterDescriptors resolveParameterDescriptors(DeclarationDescriptor containingDeclaration, PsiParameter[] parameters) {
private ValueParameterDescriptor resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
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(); PsiType psiType = parameter.getType();
JetType varargElementType; JetType varargElementType;
@@ -552,6 +607,8 @@ public class JavaDescriptorResolver {
boolean nullable = true; boolean nullable = true;
String typeFromAnnotation = null; String typeFromAnnotation = null;
boolean receiver = false;
// TODO: must be very slow, make it lazy? // TODO: must be very slow, make it lazy?
String name = parameter.getName() != null ? parameter.getName() : "p" + i; String name = parameter.getName() != null ? parameter.getName() : "p" + i;
for (PsiAnnotation annotation : parameter.getModifierList().getAnnotations()) { for (PsiAnnotation annotation : parameter.getModifierList().getAnnotations()) {
@@ -575,8 +632,16 @@ public class JavaDescriptorResolver {
if (signatureExpression != null) { if (signatureExpression != null) {
typeFromAnnotation = (String) signatureExpression.getValue(); 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())) { } 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 { } else {
outType = semanticServices.getTypeTransformer().transformToType(psiType); outType = semanticServices.getTypeTransformer().transformToType(psiType);
} }
return new ValueParameterDescriptorImpl( if (receiver) {
containingDeclaration, return JvmMethodParameterMeaning.receiver(outType);
i, } else {
Collections.<AnnotationDescriptor>emptyList(), // TODO return JvmMethodParameterMeaning.regular(new ValueParameterDescriptorImpl(
name, containingDeclaration,
null, // TODO : review i,
changeNullable ? TypeUtils.makeNullableAsSpecified(outType, nullable) : outType, Collections.<AnnotationDescriptor>emptyList(), // TODO
false, name,
varargElementType null, // TODO : review
); changeNullable ? TypeUtils.makeNullableAsSpecified(outType, nullable) : outType,
false,
varargElementType
));
}
} }
public VariableDescriptor resolveFieldToVariableDescriptor(DeclarationDescriptor containingDeclaration, PsiField field) { public VariableDescriptor resolveFieldToVariableDescriptor(DeclarationDescriptor containingDeclaration, PsiField field) {
@@ -687,11 +756,12 @@ public class JavaDescriptorResolver {
); );
methodDescriptorCache.put(method, functionDescriptorImpl); methodDescriptorCache.put(method, functionDescriptorImpl);
List<TypeParameterDescriptor> typeParameters = resolveMethodTypeParameters(method, functionDescriptorImpl); List<TypeParameterDescriptor> typeParameters = resolveMethodTypeParameters(method, functionDescriptorImpl);
ValueParameterDescriptors valueParameterDescriptors = resolveParameterDescriptors(functionDescriptorImpl, parameters);
functionDescriptorImpl.initialize( functionDescriptorImpl.initialize(
null, valueParameterDescriptors.receiverType,
DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor), DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor),
typeParameters, typeParameters,
resolveParameterDescriptors(functionDescriptorImpl, parameters), valueParameterDescriptors.descriptors,
makeReturnType(returnType, method), makeReturnType(returnType, method),
Modality.convertFromFlags(method.hasModifierProperty(PsiModifier.ABSTRACT), !method.hasModifierProperty(PsiModifier.FINAL)), Modality.convertFromFlags(method.hasModifierProperty(PsiModifier.ABSTRACT), !method.hasModifierProperty(PsiModifier.FINAL)),
resolveVisibilityFromPsiModifiers(method) resolveVisibilityFromPsiModifiers(method)
@@ -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_HAS_DEFAULT_VALUE_FIELD = "hasDefaultValue";
public static final String JET_VALUE_PARAMETER_NULLABLE_FIELD = "nullable"; 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_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"); public static final JvmClassName JET_TYPE_PARAMETER = new JvmClassName("jet.typeinfo.JetTypeParameter");
@@ -0,0 +1,3 @@
namespace test
fun Int.shuffle() = 1
@@ -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.JavaDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; 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.JetType;
import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.lang.types.Variance;
@@ -226,6 +227,12 @@ public class ReadClassDataTest extends UsefulTestCase {
serializeCommaSeparated(fun.getTypeParameters(), sb); serializeCommaSeparated(fun.getTypeParameters(), sb);
sb.append(">"); sb.append(">");
} }
if (fun.getReceiverParameter().exists()) {
serialize(fun.getReceiverParameter(), sb);
sb.append(".");
}
sb.append(fun.getName()); sb.append(fun.getName());
sb.append("("); sb.append("(");
serializeCommaSeparated(fun.getValueParameters(), sb); serializeCommaSeparated(fun.getValueParameters(), sb);
@@ -233,6 +240,10 @@ public class ReadClassDataTest extends UsefulTestCase {
serialize(fun.getReturnType(), sb); serialize(fun.getReturnType(), sb);
} }
private void serialize(ExtensionReceiver extensionReceiver, StringBuilder sb) {
serialize(extensionReceiver.getType(), sb);
}
private void serialize(PropertyDescriptor prop, StringBuilder sb) { private void serialize(PropertyDescriptor prop, StringBuilder sb) {
if (prop.isVar()) { if (prop.isVar()) {
sb.append("var "); sb.append("var ");
@@ -35,6 +35,11 @@ public @interface JetValueParameter {
*/ */
boolean hasDefaultValue () default false; boolean hasDefaultValue () default false;
/**
* @return if this parameter is receiver
*/
boolean receiver() default false;
/** /**
* @return type unless Java type is correct Kotlin type. * @return type unless Java type is correct Kotlin type.
*/ */