JS: fix behaviour of char-returning functions with multiple inheritance

See KT-19772
This commit is contained in:
Alexey Andreev
2017-09-26 12:55:53 +03:00
parent 13d6e96c2f
commit 46526db8f0
17 changed files with 401 additions and 17 deletions
@@ -0,0 +1,25 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
open class A {
fun get(index: Int): Char = '*'
}
abstract class <!WRONG_MULTIPLE_INHERITANCE!>B<!> : A(), CharSequence
interface I {
fun nextChar(): Char
}
abstract class <!WRONG_MULTIPLE_INHERITANCE!>C<!> : CharIterator(), I {
override fun nextChar(): Char = '*'
}
class <!WRONG_MULTIPLE_INHERITANCE!>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
}
@@ -0,0 +1,56 @@
package
public open class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun get(/*0*/ index: kotlin.Int): kotlin.Char
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public abstract class B : A, kotlin.CharSequence {
public constructor B()
public abstract override /*1*/ /*fake_override*/ val length: kotlin.Int
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*2*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract override /*1*/ /*fake_override*/ fun subSequence(/*0*/ startIndex: kotlin.Int, /*1*/ endIndex: kotlin.Int): kotlin.CharSequence
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public abstract class C : kotlin.collections.CharIterator, I {
public constructor C()
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract override /*1*/ /*fake_override*/ fun hasNext(): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun next(): kotlin.Char
public open override /*2*/ fun nextChar(): kotlin.Char
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class CC : kotlin.CharSequence, MyCharSequence {
public constructor CC(/*0*/ s: kotlin.CharSequence)
public open override /*2*/ /*delegation*/ val length: kotlin.Int
public final val s: kotlin.CharSequence
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*delegation*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*delegation*/ fun subSequence(/*0*/ startIndex: kotlin.Int, /*1*/ endIndex: kotlin.Int): kotlin.CharSequence
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface I {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun nextChar(): kotlin.Char
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface MyCharSequence {
public abstract val length: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract operator fun get(/*0*/ index: kotlin.Int): kotlin.Char
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun subSequence(/*0*/ startIndex: kotlin.Int, /*1*/ endIndex: kotlin.Int): kotlin.CharSequence
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -66,6 +66,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
doTest(fileName);
}
@TestMetadata("wrongMultipleInheritance.kt")
public void testWrongMultipleInheritance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/wrongMultipleInheritance.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -35,7 +35,7 @@ object JsPlatformConfigurator : PlatformConfigurator(
additionalDeclarationCheckers = listOf(
NativeInvokeChecker(), NativeGetterChecker(), NativeSetterChecker(),
JsNameChecker, JsModuleChecker, JsExternalFileChecker,
JsExternalChecker, JsInheritanceChecker,
JsExternalChecker, JsInheritanceChecker, JsMultipleInheritanceChecker,
JsRuntimeAnnotationChecker,
JsDynamicDeclarationChecker,
ExpectedActualDeclarationChecker
@@ -104,6 +104,10 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
put(ErrorsJs.EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, "External class constructor cannot have a property parameter")
put(ErrorsJs.CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION, "This property can only be used from external declarations")
put(ErrorsJs.WRONG_MULTIPLE_INHERITANCE,
"Can't apply multiple inheritance here, since it's impossible to generate bridge for system function {0}",
Renderers.DECLARATION_NAME_WITH_KIND)
this
}
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.js.resolve.diagnostics;
import com.intellij.psi.PsiElement;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.diagnostics.*;
@@ -109,6 +110,9 @@ public interface ErrorsJs {
DiagnosticFactory0<KtParameter> EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, CallableMemberDescriptor> WRONG_MULTIPLE_INHERITANCE =
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
{
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.resolve.diagnostics
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
object JsMultipleInheritanceChecker : SimpleDeclarationChecker {
private val fqNames = listOf(
FqNameUnsafe("kotlin.CharSequence.get"),
FqNameUnsafe("kotlin.collections.CharIterator.nextChar")
)
private val simpleNames = fqNames.mapTo(mutableSetOf()) { it.shortName() }
override fun check(
declaration: KtDeclaration, descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink, bindingContext: BindingContext
) {
if (descriptor !is ClassDescriptor) return
for (callable in descriptor.unsubstitutedMemberScope.getContributedDescriptors { it in simpleNames }
.filterIsInstance<CallableMemberDescriptor>()) {
if (callable.overriddenDescriptors.size > 1 && callable.overriddenDescriptors.any { it.fqNameUnsafe in fqNames }) {
diagnosticHolder.report(ErrorsJs.WRONG_MULTIPLE_INHERITANCE.on(declaration, callable))
}
}
}
}
@@ -445,6 +445,18 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/char/charUnaryOperations.kt");
doTest(fileName);
}
@TestMetadata("topLevelCallables.kt")
public void testTopLevelCallables() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/char/topLevelCallables.kt");
doTest(fileName);
}
@TestMetadata("unboxedCharSpecials.kt")
public void testUnboxedCharSpecials() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/char/unboxedCharSpecials.kt");
doTest(fileName);
}
}
@TestMetadata("js/js.translator/testData/box/classObject")
@@ -803,6 +815,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/coercion"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("bridgeChar.kt")
public void testBridgeChar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/bridgeChar.kt");
doTest(fileName);
}
@TestMetadata("classProperty.kt")
public void testClassProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/classProperty.kt");
@@ -857,6 +875,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("propertyBridgeChar.kt")
public void testPropertyBridgeChar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/propertyBridgeChar.kt");
doTest(fileName);
}
@TestMetadata("receiverSmartCast.kt")
public void testReceiverSmartCast() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/receiverSmartCast.kt");
@@ -65,7 +65,9 @@ object CallTranslator {
value: JsExpression,
extensionOrDispatchReceiver: JsExpression? = null
): JsExpression {
val variableAccessInfo = VariableAccessInfo(context.getCallInfo(resolvedCall, extensionOrDispatchReceiver), value)
val type = TranslationUtils.getReturnTypeForCoercion(resolvedCall.resultingDescriptor)
val coerceValue = TranslationUtils.coerce(context, value, type)
val variableAccessInfo = VariableAccessInfo(context.getCallInfo(resolvedCall, extensionOrDispatchReceiver), coerceValue)
val result = variableAccessInfo.translateVariableAccess().source(resolvedCall.call.callElement)
result.type = context.currentModule.builtIns.unitType
return result
@@ -51,6 +51,10 @@ public final class InitializerVisitor extends TranslatorVisitor<Void> {
KtExpression delegate = property.getDelegateExpression();
if (initializer != null) {
assert value != null;
KotlinType type = TranslationUtils.isReferenceToSyntheticBackingField(descriptor) ?
descriptor.getType() :
TranslationUtils.getReturnTypeForCoercion(descriptor);
value = TranslationUtils.coerce(context, value, type);
statement = generateInitializerForProperty(context, descriptor, value);
}
else if (delegate != null) {
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtQualifiedExpression;
@@ -84,6 +85,10 @@ public final class ReferenceTranslator {
if (parameter.getContainingDeclaration() instanceof AnonymousFunctionDescriptor) {
return DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
}
if (parameter.getContainingDeclaration() instanceof PropertySetterDescriptor) {
PropertySetterDescriptor setter = (PropertySetterDescriptor) parameter.getContainingDeclaration();
return TranslationUtils.getReturnTypeForCoercion(setter.getCorrespondingProperty(), false);
}
}
return ((CallableDescriptor) descriptor).getReturnType();
}
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.js.translate.general.Translation;
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -58,6 +59,13 @@ import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCallableDe
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*;
public final class TranslationUtils {
private static final Set<FqNameUnsafe> CLASSES_WITH_NON_BOXED_CHARS = new HashSet<>(Arrays.asList(
new FqNameUnsafe("kotlin.collections.CharIterator"),
new FqNameUnsafe("kotlin.ranges.CharProgression"),
new FqNameUnsafe("kotlin.js.internal.CharCompanionObject"),
new FqNameUnsafe("kotlin.Char.Companion"),
KotlinBuiltIns.FQ_NAMES.charSequence, KotlinBuiltIns.FQ_NAMES.number
));
private TranslationUtils() {
}
@@ -172,17 +180,21 @@ public final class TranslationUtils {
@NotNull
public static JsName getNameForBackingField(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && !(containingDescriptor instanceof PackageFragmentDescriptor)) {
if (isReferenceToSyntheticBackingField(descriptor)) {
return context.getNameForBackingField(descriptor);
}
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
return containingDescriptor instanceof PackageFragmentDescriptor ?
context.getInnerNameForDescriptor(descriptor) :
context.getNameForDescriptor(descriptor);
}
public static boolean isReferenceToSyntheticBackingField(@NotNull PropertyDescriptor descriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
return !JsDescriptorUtils.isSimpleFinalProperty(descriptor) && !(containingDescriptor instanceof PackageFragmentDescriptor);
}
@NotNull
public static JsNameRef backingFieldReference(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
@@ -196,7 +208,7 @@ public final class TranslationUtils {
}
JsNameRef result = new JsNameRef(getNameForBackingField(context, descriptor), receiver);
MetadataProperties.setType(result, getReturnTypeForCoercion(descriptor));
MetadataProperties.setType(result, getReturnTypeForCoercion(descriptor, true));
return result;
}
@@ -396,25 +408,50 @@ public final class TranslationUtils {
@NotNull
public static KotlinType getReturnTypeForCoercion(@NotNull CallableDescriptor descriptor) {
return getReturnTypeForCoercion(descriptor, false);
}
@NotNull
public static KotlinType getReturnTypeForCoercion(@NotNull CallableDescriptor descriptor, boolean forcePrivate) {
descriptor = descriptor.getOriginal();
if (FunctionTypesKt.getFunctionalClassKind(descriptor) != null || descriptor instanceof AnonymousFunctionDescriptor) {
return DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
return getAnyTypeFromSameModule(descriptor);
}
Collection<? extends CallableDescriptor> overridden = descriptor.getOverriddenDescriptors();
if (overridden.isEmpty()) {
return descriptor.getReturnType() != null ?
descriptor.getReturnType() :
DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
KotlinType returnType = descriptor.getReturnType();
if (returnType == null) {
return getAnyTypeFromSameModule(descriptor);
}
DeclarationDescriptor container = descriptor.getContainingDeclaration();
boolean isPublic = descriptor.getVisibility().effectiveVisibility(descriptor, true).getPublicApi() && !forcePrivate;
if (KotlinBuiltIns.isCharOrNullableChar(returnType) && container instanceof ClassDescriptor && isPublic) {
ClassDescriptor containingClass = (ClassDescriptor) container;
FqNameUnsafe containingClassName = DescriptorUtilsKt.getFqNameUnsafe(containingClass);
if (!CLASSES_WITH_NON_BOXED_CHARS.contains(containingClassName) &&
!KotlinBuiltIns.isPrimitiveType(containingClass.getDefaultType()) &&
!KotlinBuiltIns.isPrimitiveArray(containingClassName)
) {
return getAnyTypeFromSameModule(descriptor);
}
}
return returnType;
}
Set<KotlinType> typesFromOverriddenCallables = overridden.stream()
.map(TranslationUtils::getReturnTypeForCoercion)
.map(o -> getReturnTypeForCoercion(o, forcePrivate))
.collect(Collectors.toSet());
return typesFromOverriddenCallables.size() == 1
? typesFromOverriddenCallables.iterator().next()
: DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
: getAnyTypeFromSameModule(descriptor);
}
@NotNull
private static KotlinType getAnyTypeFromSameModule(@NotNull DeclarationDescriptor descriptor) {
return DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
}
@NotNull
@@ -435,7 +472,7 @@ public final class TranslationUtils {
.collect(Collectors.toSet());
return typesFromOverriddenCallables.size() == 1
? typesFromOverriddenCallables.iterator().next()
: DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
: getAnyTypeFromSameModule(descriptor);
}
@NotNull
+32
View File
@@ -0,0 +1,32 @@
// SKIP_MINIFICATION
fun foo(): Char = '1'
val p1: Char = '2'
var p2: Char = '3'
var p3: Char = '4'
get() = field + 1
set(value) {
field = value + 1
}
fun box(): String {
var root = eval("_")
var r = typeOf(root.foo())
if (r !== "number") return "fail1: $r"
r = typeOf(root.p1)
if (r !== "number") return "fail2: $r"
r = typeOf(root.p2)
if (r !== "number") return "fail3: $r"
r = typeOf(root.p3)
if (r !== "number") return "fail4: $r"
return "OK"
}
fun typeOf(x: dynamic): String = js("typeof x")
@@ -0,0 +1,24 @@
// EXPECTED_REACHABLE_NODES: 1099
private inline fun typeOf(x: dynamic): String = js("typeof x").unsafeCast<String>()
fun box(): String {
val arr = charArrayOf('A')
var r = typeOf(arr.iterator().asDynamic().nextChar())
if (r != "number") return "fail1: $r"
r = typeOf(arr.iterator().asDynamic().next())
if (r != "object") return "fail1a: $r"
var progression = 'A'..'Z'
r = typeOf(progression.asDynamic().first)
if (r != "number") return "fail2: $r"
r = typeOf(progression.asDynamic().last)
if (r != "number") return "fail3: $r"
r = typeOf(Char.asDynamic().MIN_HIGH_SURROGATE)
if (r != "number") return "fail4: $r"
return "OK"
}
fun getInt() = 65
+41
View File
@@ -0,0 +1,41 @@
// EXPECTED_REACHABLE_NODES: 1039
open class A {
fun foo(): Char = 'X'
}
interface I {
fun foo(): Any
}
class B : A(), I
fun typeOf(x: dynamic): String = js("typeof x")
fun box(): String {
val b = B()
val i: I = B()
val a: A = B()
val r1 = typeOf(b.asDynamic().foo())
if (r1 != "object") return "fail1: $r1"
val r2 = typeOf(i.asDynamic().foo())
if (r2 != "object") return "fail2: $r2"
val r3 = typeOf(a.asDynamic().foo())
if (r3 != "object") return "fail3: $r3"
val x4 = b.foo()
val r4 = typeOf(x4)
if (r4 != "number") return "fail4: $r4"
val x5 = i.foo()
val r5 = typeOf(x5)
if (r5 != "object") return "fail5: $r5"
val x6 = a.foo()
val r6 = typeOf(x6)
if (r6 != "number") return "fail6: $r6"
return "OK"
}
@@ -0,0 +1,70 @@
// EXPECTED_REACHABLE_NODES: 1039
open class A {
val foo: Char
get() = 'X'
var bar: Char = 'Y'
val baz: Char = 'Q'
var mutable: Char = 'W'
get() {
typeOfMutable += typeOf(field.asDynamic()) + ";"
return field + 1
}
set(value) {
typeOfMutable += typeOf(js("value")) + ";" + typeOf(value)
field = value
}
}
interface I {
val foo: Any
val bar: Any
val baz: Any
val mutable: Any
}
class B : A(), I
fun typeOf(x: dynamic): String = js("typeof x")
var typeOfMutable = ""
fun box(): String {
val a = B()
val b: I = B()
val r1 = typeOf(a.foo)
if (r1 != "number") return "fail1: $r1"
val r2 = typeOf(b.foo)
if (r2 != "object") return "fail2: $r2"
val r3 = typeOf(a.asDynamic().foo)
if (r3 != "object") return "fail3: $r3"
val r4 = typeOf(a.asDynamic().bar)
if (r4 != "object") return "fail4: $r4"
val r5 = typeOf(a.asDynamic().baz)
if (r5 != "object") return "fail5: $r5"
a.bar++
val r6 = typeOf(a.asDynamic().bar)
if (r6 != "object") return "fail6: $r6"
val r7 = typeOf(a.asDynamic().mutable)
if (r7 != "object") return "fail7: $r7"
a.mutable = 'E'
if (typeOfMutable != "number;object;number") return "fail8: $typeOfMutable"
val r9 = typeOf(a.mutable)
if (r9 != "number") return "fail9: $r9"
return "OK"
}
@@ -6,7 +6,8 @@ class CC(val s: CharSequence) : CharSequence by s, MyCharSequence {}
interface MyCharSequence {
val length: Int
operator fun get(index: Int): Char
// TODO: uncomment when it's possible to implement bridges for get/charCodeAt
//operator fun get(index: Int): Char
fun subSequence(startIndex: Int, endIndex: Int): CharSequence
}
@@ -25,17 +26,17 @@ fun box(): String {
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]}"
//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]}"
//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]}"
//if (ccc[2] != 't') return "Fail 8: ${ccc[2]}"
return "OK"
}