JS: fix behaviour of char-returning functions with multiple inheritance
See KT-19772
This commit is contained in:
@@ -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);
|
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")
|
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ object JsPlatformConfigurator : PlatformConfigurator(
|
|||||||
additionalDeclarationCheckers = listOf(
|
additionalDeclarationCheckers = listOf(
|
||||||
NativeInvokeChecker(), NativeGetterChecker(), NativeSetterChecker(),
|
NativeInvokeChecker(), NativeGetterChecker(), NativeSetterChecker(),
|
||||||
JsNameChecker, JsModuleChecker, JsExternalFileChecker,
|
JsNameChecker, JsModuleChecker, JsExternalFileChecker,
|
||||||
JsExternalChecker, JsInheritanceChecker,
|
JsExternalChecker, JsInheritanceChecker, JsMultipleInheritanceChecker,
|
||||||
JsRuntimeAnnotationChecker,
|
JsRuntimeAnnotationChecker,
|
||||||
JsDynamicDeclarationChecker,
|
JsDynamicDeclarationChecker,
|
||||||
ExpectedActualDeclarationChecker
|
ExpectedActualDeclarationChecker
|
||||||
|
|||||||
+4
@@ -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.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.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
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.js.resolve.diagnostics;
|
package org.jetbrains.kotlin.js.resolve.diagnostics;
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||||
import org.jetbrains.kotlin.diagnostics.*;
|
import org.jetbrains.kotlin.diagnostics.*;
|
||||||
@@ -109,6 +110,9 @@ public interface ErrorsJs {
|
|||||||
DiagnosticFactory0<KtParameter> EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtParameter> EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<PsiElement> CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION = 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")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
Object _initializer = new Object() {
|
Object _initializer = new Object() {
|
||||||
{
|
{
|
||||||
|
|||||||
+49
@@ -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");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/char/charUnaryOperations.kt");
|
||||||
doTest(fileName);
|
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")
|
@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);
|
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")
|
@TestMetadata("classProperty.kt")
|
||||||
public void testClassProperty() throws Exception {
|
public void testClassProperty() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/classProperty.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/classProperty.kt");
|
||||||
@@ -857,6 +875,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("receiverSmartCast.kt")
|
||||||
public void testReceiverSmartCast() throws Exception {
|
public void testReceiverSmartCast() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/receiverSmartCast.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/receiverSmartCast.kt");
|
||||||
|
|||||||
+3
-1
@@ -65,7 +65,9 @@ object CallTranslator {
|
|||||||
value: JsExpression,
|
value: JsExpression,
|
||||||
extensionOrDispatchReceiver: JsExpression? = null
|
extensionOrDispatchReceiver: JsExpression? = null
|
||||||
): JsExpression {
|
): 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)
|
val result = variableAccessInfo.translateVariableAccess().source(resolvedCall.call.callElement)
|
||||||
result.type = context.currentModule.builtIns.unitType
|
result.type = context.currentModule.builtIns.unitType
|
||||||
return result
|
return result
|
||||||
|
|||||||
+4
@@ -51,6 +51,10 @@ public final class InitializerVisitor extends TranslatorVisitor<Void> {
|
|||||||
KtExpression delegate = property.getDelegateExpression();
|
KtExpression delegate = property.getDelegateExpression();
|
||||||
if (initializer != null) {
|
if (initializer != null) {
|
||||||
assert value != 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);
|
statement = generateInitializerForProperty(context, descriptor, value);
|
||||||
}
|
}
|
||||||
else if (delegate != null) {
|
else if (delegate != null) {
|
||||||
|
|||||||
+5
@@ -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.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
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.name.FqNameUnsafe;
|
||||||
import org.jetbrains.kotlin.psi.KtExpression;
|
import org.jetbrains.kotlin.psi.KtExpression;
|
||||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression;
|
import org.jetbrains.kotlin.psi.KtQualifiedExpression;
|
||||||
@@ -84,6 +85,10 @@ public final class ReferenceTranslator {
|
|||||||
if (parameter.getContainingDeclaration() instanceof AnonymousFunctionDescriptor) {
|
if (parameter.getContainingDeclaration() instanceof AnonymousFunctionDescriptor) {
|
||||||
return DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
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();
|
return ((CallableDescriptor) descriptor).getReturnType();
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-11
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.js.translate.general.Translation;
|
|||||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
|
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
|
||||||
import org.jetbrains.kotlin.name.ClassId;
|
import org.jetbrains.kotlin.name.ClassId;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
|
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
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.*;
|
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*;
|
||||||
|
|
||||||
public final class TranslationUtils {
|
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() {
|
private TranslationUtils() {
|
||||||
}
|
}
|
||||||
@@ -172,17 +180,21 @@ public final class TranslationUtils {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsName getNameForBackingField(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
|
public static JsName getNameForBackingField(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
|
||||||
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
if (isReferenceToSyntheticBackingField(descriptor)) {
|
||||||
|
|
||||||
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && !(containingDescriptor instanceof PackageFragmentDescriptor)) {
|
|
||||||
return context.getNameForBackingField(descriptor);
|
return context.getNameForBackingField(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
||||||
return containingDescriptor instanceof PackageFragmentDescriptor ?
|
return containingDescriptor instanceof PackageFragmentDescriptor ?
|
||||||
context.getInnerNameForDescriptor(descriptor) :
|
context.getInnerNameForDescriptor(descriptor) :
|
||||||
context.getNameForDescriptor(descriptor);
|
context.getNameForDescriptor(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isReferenceToSyntheticBackingField(@NotNull PropertyDescriptor descriptor) {
|
||||||
|
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
||||||
|
return !JsDescriptorUtils.isSimpleFinalProperty(descriptor) && !(containingDescriptor instanceof PackageFragmentDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsNameRef backingFieldReference(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
|
public static JsNameRef backingFieldReference(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
|
||||||
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
||||||
@@ -196,7 +208,7 @@ public final class TranslationUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsNameRef result = new JsNameRef(getNameForBackingField(context, descriptor), receiver);
|
JsNameRef result = new JsNameRef(getNameForBackingField(context, descriptor), receiver);
|
||||||
MetadataProperties.setType(result, getReturnTypeForCoercion(descriptor));
|
MetadataProperties.setType(result, getReturnTypeForCoercion(descriptor, true));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -396,25 +408,50 @@ public final class TranslationUtils {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static KotlinType getReturnTypeForCoercion(@NotNull CallableDescriptor descriptor) {
|
public static KotlinType getReturnTypeForCoercion(@NotNull CallableDescriptor descriptor) {
|
||||||
|
return getReturnTypeForCoercion(descriptor, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static KotlinType getReturnTypeForCoercion(@NotNull CallableDescriptor descriptor, boolean forcePrivate) {
|
||||||
descriptor = descriptor.getOriginal();
|
descriptor = descriptor.getOriginal();
|
||||||
|
|
||||||
if (FunctionTypesKt.getFunctionalClassKind(descriptor) != null || descriptor instanceof AnonymousFunctionDescriptor) {
|
if (FunctionTypesKt.getFunctionalClassKind(descriptor) != null || descriptor instanceof AnonymousFunctionDescriptor) {
|
||||||
return DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
return getAnyTypeFromSameModule(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<? extends CallableDescriptor> overridden = descriptor.getOverriddenDescriptors();
|
Collection<? extends CallableDescriptor> overridden = descriptor.getOverriddenDescriptors();
|
||||||
if (overridden.isEmpty()) {
|
if (overridden.isEmpty()) {
|
||||||
return descriptor.getReturnType() != null ?
|
KotlinType returnType = descriptor.getReturnType();
|
||||||
descriptor.getReturnType() :
|
if (returnType == null) {
|
||||||
DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
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()
|
Set<KotlinType> typesFromOverriddenCallables = overridden.stream()
|
||||||
.map(TranslationUtils::getReturnTypeForCoercion)
|
.map(o -> getReturnTypeForCoercion(o, forcePrivate))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
return typesFromOverriddenCallables.size() == 1
|
return typesFromOverriddenCallables.size() == 1
|
||||||
? typesFromOverriddenCallables.iterator().next()
|
? 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
|
@NotNull
|
||||||
@@ -435,7 +472,7 @@ public final class TranslationUtils {
|
|||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
return typesFromOverriddenCallables.size() == 1
|
return typesFromOverriddenCallables.size() == 1
|
||||||
? typesFromOverriddenCallables.iterator().next()
|
? typesFromOverriddenCallables.iterator().next()
|
||||||
: DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
: getAnyTypeFromSameModule(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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 {
|
interface MyCharSequence {
|
||||||
val length: Int
|
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
|
fun subSequence(startIndex: Int, endIndex: Int): CharSequence
|
||||||
}
|
}
|
||||||
@@ -25,17 +26,17 @@ fun box(): String {
|
|||||||
val cc: CharSequence = CC(kotlin)
|
val cc: CharSequence = CC(kotlin)
|
||||||
if (cc.length != 6) return "Fail 3: ${cc.length}"
|
if (cc.length != 6) return "Fail 3: ${cc.length}"
|
||||||
if (cc.subSequence(0, 3) != kot) return "Fail 4"
|
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)
|
val mcc: MyCharSequence = CC(kotlin)
|
||||||
if (mcc.length != 6) return "Fail 6: ${mcc.length}"
|
if (mcc.length != 6) return "Fail 6: ${mcc.length}"
|
||||||
if (mcc.subSequence(0, 3) != kot) return "Fail 7"
|
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)
|
val ccc = CC(cc)
|
||||||
if (ccc.length != 6) return "Fail 6: ${ccc.length}"
|
if (ccc.length != 6) return "Fail 6: ${ccc.length}"
|
||||||
if (ccc.subSequence(0, 3) != kot) return "Fail 7"
|
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"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user