From 847ec9e5508019ecba63aa1e3f2a70bc8026f4ac Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Fri, 20 Jan 2017 14:06:06 +0300 Subject: [PATCH] JS: fixed subSequence in CharSequence descendants (KT-14035) + added support for function intrics in delegation --- .../kotlin/js/naming/NameSuggestion.kt | 1 - js/js.libraries/src/core/builtins.kt | 12 ++++++++- .../functions/factories/TopLevelFIF.java | 15 +++++++++++ .../kotlin/js/translate/utils/utils.kt | 10 +++++++- .../box/expression/stringClass/subSequence.kt | 25 +++++++++++++++++++ 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt index c2b653dcd5f..bcf43bd698c 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt @@ -227,7 +227,6 @@ class NameSuggestion { if (overriddenDescriptor is FunctionDescriptor) { when (overriddenDescriptor.fqNameUnsafe.asString()) { - "kotlin.CharSequence.subSequence" -> return NameAndStability("substring", true) "kotlin.CharSequence.get" -> return NameAndStability("charAt", true) "kotlin.Any.equals" -> return NameAndStability("equals", true) } diff --git a/js/js.libraries/src/core/builtins.kt b/js/js.libraries/src/core/builtins.kt index 3ce95f5a593..ad935517732 100644 --- a/js/js.libraries/src/core/builtins.kt +++ b/js/js.libraries/src/core/builtins.kt @@ -36,4 +36,14 @@ internal fun arrayIterator(array: dynamic): MutableIterator { internal class PropertyMetadata(@JsName("callableName") val name: String) @JsName("noWhenBranchMatched") -internal fun noWhenBranchMatched(): Nothing = throw NoWhenBranchMatchedException() \ No newline at end of file +internal fun noWhenBranchMatched(): Nothing = throw NoWhenBranchMatchedException() + +@JsName("subSequence") +fun subSequence(c: CharSequence, startIndex: Int, endIndex: Int): CharSequence { + if (c is String) { + return c.substring(startIndex, endIndex) + } + else { + return c.asDynamic().`subSequence_vux9f0$`(startIndex, endIndex) + } +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java index 962b3ce1a37..3ab22459212 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -63,6 +63,9 @@ public final class TopLevelFIF extends CompositeFIF { @NotNull public static final KotlinFunctionIntrinsic KOTLIN_EQUALS = new KotlinFunctionIntrinsic("equals"); + @NotNull + public static final KotlinFunctionIntrinsic KOTLIN_SUBSEQUENCE = new KotlinFunctionIntrinsic("subSequence"); + @NotNull private static final DescriptorPredicate HASH_CODE_IN_ANY = pattern("kotlin", "Any", "hashCode"); @NotNull @@ -145,6 +148,16 @@ public final class TopLevelFIF extends CompositeFIF { } }; + private static final FunctionIntrinsic STRING_SUBSTRING = new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply( + @Nullable JsExpression receiver, @NotNull List arguments, @NotNull TranslationContext context + ) { + return new JsInvocation(new JsNameRef("substring", receiver), arguments); + } + }; + @NotNull public static final KotlinFunctionIntrinsic TO_STRING = new KotlinFunctionIntrinsic("toString"); @@ -159,6 +172,8 @@ public final class TopLevelFIF extends CompositeFIF { add(HASH_CODE_IN_ANY, KOTLIN_HASH_CODE); add(pattern(NamePredicate.PRIMITIVE_NUMBERS, "equals"), KOTLIN_EQUALS); add(pattern("String|Boolean|Char|Number.equals"), KOTLIN_EQUALS); + add(pattern("String.subSequence"), STRING_SUBSTRING); + add(pattern("CharSequence.subSequence"), KOTLIN_SUBSEQUENCE); add(pattern("kotlin", "iterator").isExtensionOf(FQ_NAMES.iterator.asString()), RETURN_RECEIVER_INTRINSIC); add(pattern("kotlin.js", "Json", "get"), ArrayFIF.GET_INTRINSIC); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index fa1a6f9ad81..56ea513326c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -63,7 +63,15 @@ fun generateDelegateCall( args.add(JsNameRef(jsParamName)) } - val functionObject = simpleReturnFunction(context.getScopeForDescriptor(fromDescriptor), JsInvocation(overriddenMemberFunctionRef, args)) + val intrinsic = context.intrinsics().getFunctionIntrinsic(toDescriptor) + val invocation = if (intrinsic.exists()) { + intrinsic.apply(thisObject, args, context) + } + else { + JsInvocation(overriddenMemberFunctionRef, args) + } + + val functionObject = simpleReturnFunction(context.getScopeForDescriptor(fromDescriptor), invocation) functionObject.parameters.addAll(parameters) context.addFunctionToPrototype(classDescriptor, fromDescriptor, functionObject) diff --git a/js/js.translator/testData/box/expression/stringClass/subSequence.kt b/js/js.translator/testData/box/expression/stringClass/subSequence.kt index 025a49d6343..c3e1838fdcc 100644 --- a/js/js.translator/testData/box/expression/stringClass/subSequence.kt +++ b/js/js.translator/testData/box/expression/stringClass/subSequence.kt @@ -1,5 +1,15 @@ package foo +class CC(val s: CharSequence) : CharSequence by s, MyCharSequence {} + +interface MyCharSequence { + val length: Int + + operator fun get(index: Int): Char + + fun subSequence(startIndex: Int, endIndex: Int): CharSequence +} + fun box(): String { val kotlin: String = "kotlin" @@ -11,5 +21,20 @@ fun box(): String { val tlin = (kotlin as CharSequence).subSequence(2, 6) if (tlin.toString() != "tlin") return "Fail 2: $tlin" + val cc: CharSequence = CC(kotlin) + if (cc.length != 6) return "Fail 3: ${cc.length}" + if (cc.subSequence(0, 3) != kot) return "Fail 4" + if (cc[2] != 't') return "Fail 5: ${cc[2]}" + + val mcc: MyCharSequence = CC(kotlin) + if (mcc.length != 6) return "Fail 6: ${mcc.length}" + if (mcc.subSequence(0, 3) != kot) return "Fail 7" + if (mcc[2] != 't') return "Fail 8: ${mcc[2]}" + + val ccc = CC(cc) + if (ccc.length != 6) return "Fail 6: ${ccc.length}" + if (ccc.subSequence(0, 3) != kot) return "Fail 7" + if (ccc[2] != 't') return "Fail 8: ${ccc[2]}" + return "OK" }