diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index 83338ed091b..a07dc71387a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -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 namedMethods = new HashMap(); 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 diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicsMap.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicsMap.java index 49e585ce927..2371bedb8b7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicsMap.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicsMap.java @@ -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); + } } diff --git a/compiler/testData/codegen/boxWithStdlib/strings/stringPlusOnlyWorksOnString.kt b/compiler/testData/codegen/boxWithStdlib/strings/stringPlusOnlyWorksOnString.kt new file mode 100644 index 00000000000..e9d981d8edc --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/strings/stringPlusOnlyWorksOnString.kt @@ -0,0 +1,8 @@ +import java.util.ArrayList + +fun box(): String { + var x: MutableCollection = ArrayList() + x + ArrayList() + x += ArrayList() + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 841380e34b7..86b2abac88a 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -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")