[JS IR] Allow value classes in external decls

Instances of value classes are passed unboxed, unless the instance is
nullable _and_ the value class wraps another nullable value.

#KT-43224 Fixed
This commit is contained in:
Sergej Jaskiewicz
2021-11-29 21:51:29 +00:00
committed by Space
parent 3f47725eb9
commit 887e91328f
12 changed files with 1974 additions and 3 deletions
@@ -268,6 +268,9 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
if (!isIrBackendEnabled()) {
this[LanguageFeature.JsAllowInvalidCharsIdentifiersEscaping] = LanguageFeature.State.DISABLED
}
if (isIrBackendEnabled()) {
this[LanguageFeature.JsAllowValueClassesInExternals] = LanguageFeature.State.ENABLED
}
}
}
}
@@ -88,6 +88,10 @@ class LanguageVersionSettingsBuilder {
}
}
if (targetBackend?.isIR == true) {
specificFeatures[LanguageFeature.JsAllowValueClassesInExternals] = LanguageFeature.State.ENABLED
}
directives[LanguageSettingsDirectives.LANGUAGE].forEach { parseLanguageFeature(it) }
}
@@ -0,0 +1,64 @@
// !LANGUAGE: +InlineClasses, -JvmInlineValueClasses, +JsAllowValueClassesInExternals
// FILE: uint.kt
package kotlin
inline class UInt(private val i: Int)
// FILE: test.kt
inline class SomeIC(val a: Int)
external val l: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
external val ll
get(): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!> = definedExternally
external var r: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
external var rr: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
get() = definedExternally
set(<!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>v: SomeIC<!>) { definedExternally }
external fun foo(): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
external fun foo(<!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>c: SomeIC<!>): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
external fun foo(a: Int, <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>c: SomeIC<!>): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
external fun foo(a: Int, <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!><!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: SomeIC<!>)
external fun foo(a: Int, <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>ui: UInt<!>, <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>vararg args: UInt<!>)
external class CC(
<!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>a: SomeIC<!>,
<!EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>val b: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!><!>,
<!EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>var c: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!><!>
) {
val l: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
var r: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(<!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>c: SomeIC<!>): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(a: Int, <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>c: SomeIC<!>): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
class N(
<!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>a: SomeIC<!>,
<!EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>val b: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!><!>,
<!EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>var c: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!><!>
) {
val l: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
var r: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(<!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>c: SomeIC<!>): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(a: Int, <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>c: SomeIC<!>): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
}
}
external interface EI {
val l: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
var r: <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(<!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>c: SomeIC<!>): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
fun foo(a: Int, <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>c: SomeIC<!>): <!INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING!>SomeIC<!>
}
@@ -0,0 +1,69 @@
package
public external val l: SomeIC
public external val ll: SomeIC
public external var r: SomeIC
public external var rr: SomeIC
public external fun foo(): SomeIC
public external fun foo(/*0*/ c: SomeIC): SomeIC
public external fun foo(/*0*/ a: kotlin.Int, /*1*/ c: SomeIC): SomeIC
public external fun foo(/*0*/ a: kotlin.Int, /*1*/ vararg args: SomeIC /*kotlin.Array<out SomeIC>*/): kotlin.Unit
public external fun foo(/*0*/ a: kotlin.Int, /*1*/ ui: kotlin.UInt, /*2*/ vararg args: kotlin.UInt /*kotlin.UIntArray*/): kotlin.Unit
public final external class CC {
public constructor CC(/*0*/ a: SomeIC, /*1*/ b: SomeIC, /*2*/ c: SomeIC)
public final val b: SomeIC
public final var c: SomeIC
public final val l: SomeIC
public final var r: SomeIC
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): SomeIC
public final fun foo(/*0*/ c: SomeIC): SomeIC
public final fun foo(/*0*/ a: kotlin.Int, /*1*/ c: SomeIC): SomeIC
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final class N {
public constructor N(/*0*/ a: SomeIC, /*1*/ b: SomeIC, /*2*/ c: SomeIC)
public final val b: SomeIC
public final var c: SomeIC
public final val l: SomeIC
public final var r: SomeIC
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): SomeIC
public final fun foo(/*0*/ c: SomeIC): SomeIC
public final fun foo(/*0*/ a: kotlin.Int, /*1*/ c: SomeIC): SomeIC
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public external interface EI {
public abstract val l: SomeIC
public abstract var r: SomeIC
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract fun foo(): SomeIC
public abstract fun foo(/*0*/ c: SomeIC): SomeIC
public abstract fun foo(/*0*/ a: kotlin.Int, /*1*/ c: SomeIC): SomeIC
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final inline class SomeIC {
public constructor SomeIC(/*0*/ a: kotlin.Int)
public final val a: kotlin.Int
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
package kotlin {
public final inline class UInt {
public constructor UInt(/*0*/ i: kotlin.Int)
private final val i: kotlin.Int
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
}
@@ -857,6 +857,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
runTest("compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClass.kt");
}
@Test
@TestMetadata("inlineClassAsParameterOrReturnType_allowed.kt.kt")
public void testInlineClassAsParameterOrReturnType_allowed_kt() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType_allowed.kt.kt");
}
@Test
@TestMetadata("inlineClassAsParameterOrReturnType.kt.kt")
public void testInlineClassAsParameterOrReturnType_kt() throws Exception {
@@ -267,7 +267,8 @@ enum class LanguageFeature(
ProhibitComparisonOfIncompatibleClasses(sinceVersion = null, kind = BUG_FIX, defaultState = State.DISABLED),
ExplicitBackingFields(sinceVersion = null, defaultState = State.DISABLED, kind = UNSTABLE_FEATURE),
FunctionalTypeWithExtensionAsSupertype(sinceVersion = KOTLIN_1_6, defaultState = State.DISABLED),
JsAllowInvalidCharsIdentifiersEscaping(sinceVersion = null, defaultState = State.DISABLED, kind = UNSTABLE_FEATURE)
JsAllowInvalidCharsIdentifiersEscaping(sinceVersion = null, defaultState = State.DISABLED, kind = UNSTABLE_FEATURE),
JsAllowValueClassesInExternals(sinceVersion = null, defaultState = State.DISABLED, kind = UNSTABLE_FEATURE)
;
@@ -29,7 +29,8 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
put(ErrorsJs.NESTED_EXTERNAL_DECLARATION, "Non top-level `external` declaration")
put(ErrorsJs.WRONG_EXTERNAL_DECLARATION, "Declaration of such kind ({0}) can''t be external", STRING)
put(ErrorsJs.EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION, "Function types with receiver are prohibited in external declarations")
put(ErrorsJs.INLINE_CLASS_IN_EXTERNAL_DECLARATION, "Using inline classes as parameter type or return type of external declarations is not supported")
put(ErrorsJs.INLINE_CLASS_IN_EXTERNAL_DECLARATION, "Using value classes as parameter type or return type of external declarations is not supported")
put(ErrorsJs.INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING, "Using value classes as parameter type or return type of external declarations is experimental")
put(ErrorsJs.JS_NAME_CLASH, "JavaScript name ({0}) generated for this declaration clashes with another declaration: {1}",
STRING, Renderers.COMPACT)
@@ -33,6 +33,7 @@ public interface ErrorsJs {
DiagnosticFactory0<KtElement> EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory0<KtExpression> NESTED_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory0<KtElement> INLINE_CLASS_IN_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory0<KtElement> INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory2<KtElement, String, DeclarationDescriptor> JS_NAME_CLASH = DiagnosticFactory2.create(
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
@@ -119,7 +119,13 @@ object JsExternalChecker : DeclarationChecker {
}
}
reportOnParametersAndReturnTypesIf(ErrorsJs.INLINE_CLASS_IN_EXTERNAL_DECLARATION, KotlinType::isInlineClassType)
val valueClassInExternalDiagnostic =
if (context.languageVersionSettings.supportsFeature(LanguageFeature.JsAllowValueClassesInExternals))
ErrorsJs.INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING
else
ErrorsJs.INLINE_CLASS_IN_EXTERNAL_DECLARATION
reportOnParametersAndReturnTypesIf(valueClassInExternalDiagnostic, KotlinType::isInlineClassType)
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.JsEnableExtensionFunctionInExternals)) {
reportOnParametersAndReturnTypesIf(ErrorsJs.EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION, KotlinType::isExtensionFunctionType)
}
@@ -7824,6 +7824,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/native/useClassFromInlineFun.kt");
}
@Test
@TestMetadata("valueClass.kt")
public void testValueClass() throws Exception {
runTest("js/js.translator/testData/box/native/valueClass.kt");
}
@Test
@TestMetadata("vararg.kt")
public void testVararg() throws Exception {
+150
View File
@@ -0,0 +1,150 @@
function NativeFoo(s) {
this.s = s;
}
NativeFoo.prototype.toString = function () {
return 'NativeFoo(\'' + this.s + '\')'
};
function _describeValue(x) {
return String(x) + ' (' + typeof x + ')'
}
function describeValueOfProperty(o, name) {
o = o == null ? globalThis : o;
return _describeValue(o[name]);
}
function nullifyTestProperties(o) {
o = o == null ? globalThis : o;
o.intWrapper = null;
o.intWrapperN = null;
o.intNWrapper = null;
o.intNWrapperN = null;
o.fooWrapper = null;
o.fooWrapperN = null;
o.fooNWrapper = null;
o.fooNWrapperN = null;
o.nativeFooWrapper = null;
o.nativeFooWrapperN = null;
o.nativeFooNWrapper = null;
o.nativeFooNWrapperN = null;
}
function defineTestMethodsAndPropertiesOnObject(o) {
o.describeIntWrapper = _describeValue;
o.describeIntWrapperN = _describeValue;
o.describeIntNWrapper = _describeValue;
o.describeIntNWrapperN = _describeValue;
o.describeFooWrapper = _describeValue;
o.describeFooWrapperN = _describeValue;
o.describeFooNWrapper = _describeValue;
o.describeFooNWrapperN = _describeValue;
o.describeNativeFooWrapper = _describeValue;
o.describeNativeFooWrapperN = _describeValue;
o.describeNativeFooNWrapper = _describeValue;
o.describeNativeFooNWrapperN = _describeValue;
nullifyTestProperties(o);
o.getIntWrapper = function () { return this.intWrapper; };
o.getIntWrapperN = function () { return this.intWrapperN; };
o.getIntNWrapper = function () { return this.intNWrapper; };
o.getIntNWrapperN = function () { return this.intNWrapperN; };
o.getFooWrapper = function () { return this.fooWrapper; };
o.getFooWrapperN = function () { return this.fooWrapperN; };
o.getFooNWrapper = function () { return this.fooNWrapper; };
o.getFooNWrapperN = function () { return this.fooNWrapperN; };
o.getNativeFooWrapper = function () { return this.nativeFooWrapper; };
o.getNativeFooWrapperN = function () { return this.nativeFooWrapperN; };
o.getNativeFooNWrapper = function () { return this.nativeFooNWrapper; };
o.getNativeFooNWrapperN = function () { return this.nativeFooNWrapperN; };
Object.defineProperties(o, {
readOnlyIntWrapper: {
get: o.getIntWrapper
},
readOnlyIntWrapperN: {
get: o.getIntWrapperN
},
readOnlyIntNWrapper: {
get: o.getIntNWrapper
},
readOnlyIntNWrapperN: {
get: o.getIntNWrapperN
},
readOnlyFooWrapper: {
get: o.getFooWrapper
},
readOnlyFooWrapperN: {
get: o.getFooWrapperN
},
readOnlyFooNWrapper: {
get: o.getFooNWrapper
},
readOnlyFooNWrapperN: {
get: o.getFooNWrapperN
},
readOnlyNativeFooWrapper: {
get: o.getNativeFooWrapper
},
readOnlyNativeFooWrapperN: {
get: o.getNativeFooWrapperN
},
readOnlyNativeFooNWrapper: {
get: o.getNativeFooNWrapper
},
readOnlyNativeFooNWrapperN: {
get: o.getNativeFooNWrapperN
},
});
}
defineTestMethodsAndPropertiesOnObject(globalThis);
function TestClass(
intWrapper,
intWrapperN,
intNWrapper,
intNWrapperN,
fooWrapper,
fooWrapperN,
fooNWrapper,
fooNWrapperN,
nativeFooWrapper,
nativeFooWrapperN,
nativeFooNWrapper,
nativeFooNWrapperN
) {
defineTestMethodsAndPropertiesOnObject(this);
this.intWrapper = intWrapper;
this.intWrapperN = intWrapperN;
this.intNWrapper = intNWrapper;
this.intNWrapperN = intNWrapperN;
this.fooWrapper = fooWrapper;
this.fooWrapperN = fooWrapperN;
this.fooNWrapper = fooNWrapper;
this.fooNWrapperN = fooNWrapperN;
this.nativeFooWrapper = nativeFooWrapper;
this.nativeFooWrapperN = nativeFooWrapperN;
this.nativeFooNWrapper = nativeFooNWrapper;
this.nativeFooNWrapperN = nativeFooNWrapperN;
}
defineTestMethodsAndPropertiesOnObject(TestClass);
var TestObject = {};
defineTestMethodsAndPropertiesOnObject(TestObject);
function makeEmptyTestClassInstance() {
var o = new TestClass();
nullifyTestProperties(o);
return o;
}
function makeTestInterfaceInstance() {
return makeEmptyTestClassInstance();
}
File diff suppressed because it is too large Load Diff