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.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils; 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.java.JvmPrimitiveType;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions; 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 org.jetbrains.jet.lang.types.lang.PrimitiveType;
import java.util.HashMap; import java.util.HashMap;
@@ -56,6 +59,9 @@ public class IntrinsicMethods {
private static final EnumValueOf ENUM_VALUE_OF = new EnumValueOf(); private static final EnumValueOf ENUM_VALUE_OF = new EnumValueOf();
private static final ToString TO_STRING = new ToString(); 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 final Map<String, IntrinsicMethod> namedMethods = new HashMap<String, IntrinsicMethod>();
private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator(); private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator();
private final IntrinsicsMap intrinsicsMap = new IntrinsicsMap(); private final IntrinsicsMap intrinsicsMap = new IntrinsicsMap();
@@ -111,11 +117,11 @@ public class IntrinsicMethods {
declareIntrinsicFunction("CharSequence", "get", 1, new StringGetChar()); declareIntrinsicFunction("CharSequence", "get", 1, new StringGetChar());
declareIntrinsicFunction("String", "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, KOTLIN_ANY_FQ_NAME, "toString", 0, TO_STRING);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "equals", 1, EQUALS); intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "equals", 1, EQUALS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "identityEquals", 1, IDENTITY_EQUALS); intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "identityEquals", 1, IDENTITY_EQUALS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "plus", 1, STRING_PLUS); intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_STRING_FQ_NAME, "plus", 1, STRING_PLUS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, "arrayOfNulls", 1, new NewArray()); intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray());
for (PrimitiveType type : PrimitiveType.values()) { for (PrimitiveType type : PrimitiveType.values()) {
String typeName = type.getTypeName().asString(); String typeName = type.getTypeName().asString();
@@ -171,7 +177,8 @@ public class IntrinsicMethods {
int arity, int arity,
@NotNull IntrinsicMethod implementation @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 @Nullable
@@ -20,7 +20,9 @@ import com.google.common.collect.Maps;
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.CallableMemberDescriptor; 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.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
@@ -30,11 +32,13 @@ import java.util.Map;
class IntrinsicsMap { class IntrinsicsMap {
private static final class Key { private static final class Key {
private final FqNameUnsafe owner; private final FqNameUnsafe owner;
private final FqName receiverParameter;
private final String name; private final String name;
private final int valueParameterCount; 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.owner = owner;
this.receiverParameter = receiverParameter;
this.name = name; this.name = name;
this.valueParameterCount = valueParameterCount; this.valueParameterCount = valueParameterCount;
} }
@@ -49,6 +53,7 @@ class IntrinsicsMap {
if (valueParameterCount != key.valueParameterCount) return false; if (valueParameterCount != key.valueParameterCount) return false;
if (!name.equals(key.name)) return false; if (!name.equals(key.name)) return false;
if (!owner.equals(key.owner)) return false; if (!owner.equals(key.owner)) return false;
if (receiverParameter == null ? key.receiverParameter != null : !receiverParameter.equals(key.receiverParameter)) return false;
return true; return true;
} }
@@ -58,6 +63,7 @@ class IntrinsicsMap {
int result = owner.hashCode(); int result = owner.hashCode();
result = 31 * result + name.hashCode(); result = 31 * result + name.hashCode();
result = 31 * result + valueParameterCount; result = 31 * result + valueParameterCount;
result = 31 * result + (receiverParameter != null ? receiverParameter.hashCode() : 0);
return result; return result;
} }
} }
@@ -77,18 +83,35 @@ class IntrinsicsMap {
/** /**
* @param valueParameterCount -1 for property * @param valueParameterCount -1 for property
*/ */
public void registerIntrinsic(@NotNull FqName owner, @NotNull String name, int valueParameterCount, @NotNull IntrinsicMethod impl) { public void registerIntrinsic(
intrinsicsMap.put(new Key(owner.toUnsafe(), name, valueParameterCount), impl); @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 @Nullable
public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) { public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) {
Key key = new Key( Key key = new Key(
DescriptorUtils.getFqName(descriptor.getContainingDeclaration()), DescriptorUtils.getFqName(descriptor.getContainingDeclaration()),
getReceiverParameterFqName(descriptor),
descriptor.getName().asString(), descriptor.getName().asString(),
valueParameterCountForKey(descriptor) valueParameterCountForKey(descriptor)
); );
return intrinsicsMap.get(key); 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"); 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") @TestMetadata("compiler/testData/codegen/boxWithStdlib/toArray")