Store receiver parameter in JVM intrinsics map

To differentiate between "String?.plus" extension in builtins and
"Iterable<*>.plus" extension in stdlib (they have the same owner, name and
value parameter count)
This commit is contained in:
Alexander Udalov
2014-02-26 22:03:12 +04:00
parent 9bf51f630d
commit b3a9721571
4 changed files with 53 additions and 10 deletions
@@ -22,9 +22,12 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lang.types.lang.PrimitiveType;
import java.util.HashMap;
@@ -56,6 +59,9 @@ public class IntrinsicMethods {
private static final EnumValueOf ENUM_VALUE_OF = new EnumValueOf();
private static final ToString TO_STRING = new ToString();
private static final FqName KOTLIN_ANY_FQ_NAME = DescriptorUtils.getFqNameSafe(KotlinBuiltIns.getInstance().getAny());
private static final FqName KOTLIN_STRING_FQ_NAME = DescriptorUtils.getFqNameSafe(KotlinBuiltIns.getInstance().getString());
private final Map<String, IntrinsicMethod> namedMethods = new HashMap<String, IntrinsicMethod>();
private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator();
private final IntrinsicsMap intrinsicsMap = new IntrinsicsMap();
@@ -111,11 +117,11 @@ public class IntrinsicMethods {
declareIntrinsicFunction("CharSequence", "get", 1, new StringGetChar());
declareIntrinsicFunction("String", "get", 1, new StringGetChar());
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "toString", 0, TO_STRING);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "equals", 1, EQUALS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "identityEquals", 1, IDENTITY_EQUALS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "plus", 1, STRING_PLUS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "arrayOfNulls", 1, new NewArray());
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "toString", 0, TO_STRING);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "equals", 1, EQUALS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "identityEquals", 1, IDENTITY_EQUALS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_STRING_FQ_NAME, "plus", 1, STRING_PLUS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray());
for (PrimitiveType type : PrimitiveType.values()) {
String typeName = type.getTypeName().asString();
@@ -171,7 +177,8 @@ public class IntrinsicMethods {
int arity,
@NotNull IntrinsicMethod implementation
) {
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(className)), methodName, arity, implementation);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(className)),
null, methodName, arity, implementation);
}
@Nullable
@@ -20,7 +20,9 @@ import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
@@ -30,11 +32,13 @@ import java.util.Map;
class IntrinsicsMap {
private static final class Key {
private final FqNameUnsafe owner;
private final FqName receiverParameter;
private final String name;
private final int valueParameterCount;
private Key(@NotNull FqNameUnsafe owner, @NotNull String name, int valueParameterCount) {
private Key(@NotNull FqNameUnsafe owner, @Nullable FqName receiverParameter, @NotNull String name, int valueParameterCount) {
this.owner = owner;
this.receiverParameter = receiverParameter;
this.name = name;
this.valueParameterCount = valueParameterCount;
}
@@ -49,6 +53,7 @@ class IntrinsicsMap {
if (valueParameterCount != key.valueParameterCount) return false;
if (!name.equals(key.name)) return false;
if (!owner.equals(key.owner)) return false;
if (receiverParameter == null ? key.receiverParameter != null : !receiverParameter.equals(key.receiverParameter)) return false;
return true;
}
@@ -58,6 +63,7 @@ class IntrinsicsMap {
int result = owner.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + valueParameterCount;
result = 31 * result + (receiverParameter != null ? receiverParameter.hashCode() : 0);
return result;
}
}
@@ -77,18 +83,35 @@ class IntrinsicsMap {
/**
* @param valueParameterCount -1 for property
*/
public void registerIntrinsic(@NotNull FqName owner, @NotNull String name, int valueParameterCount, @NotNull IntrinsicMethod impl) {
intrinsicsMap.put(new Key(owner.toUnsafe(), name, valueParameterCount), impl);
public void registerIntrinsic(
@NotNull FqName owner,
@Nullable FqName receiverParameter,
@NotNull String name,
int valueParameterCount,
@NotNull IntrinsicMethod impl
) {
intrinsicsMap.put(new Key(owner.toUnsafe(), receiverParameter, name, valueParameterCount), impl);
}
@Nullable
public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) {
Key key = new Key(
DescriptorUtils.getFqName(descriptor.getContainingDeclaration()),
getReceiverParameterFqName(descriptor),
descriptor.getName().asString(),
valueParameterCountForKey(descriptor)
);
return intrinsicsMap.get(key);
}
@Nullable
private static FqName getReceiverParameterFqName(@NotNull CallableMemberDescriptor descriptor) {
ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
if (receiverParameter == null) return null;
ClassifierDescriptor classifier = receiverParameter.getType().getConstructor().getDeclarationDescriptor();
if (classifier == null) return null;
return DescriptorUtils.getFqNameSafe(classifier);
}
}
@@ -0,0 +1,8 @@
import java.util.ArrayList
fun box(): String {
var x: MutableCollection<Int> = ArrayList()
x + ArrayList()
x += ArrayList()
return "OK"
}
@@ -1041,6 +1041,11 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/strings/forInString.kt");
}
@TestMetadata("stringPlusOnlyWorksOnString.kt")
public void testStringPlusOnlyWorksOnString() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/strings/stringPlusOnlyWorksOnString.kt");
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/toArray")