[JS IR] Replace calls with invalid type arguments for type parameters with call to errorCode function from runtime.
This commit is contained in:
+1
-2
@@ -16,8 +16,6 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|
||||||
|
|
||||||
class CallsLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
class CallsLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||||
private val transformers = listOf(
|
private val transformers = listOf(
|
||||||
@@ -32,6 +30,7 @@ class CallsLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
|||||||
BuiltInConstructorCalls(context),
|
BuiltInConstructorCalls(context),
|
||||||
JsonIntrinsics(context),
|
JsonIntrinsics(context),
|
||||||
NativeGetterSetterTransformer(context),
|
NativeGetterSetterTransformer(context),
|
||||||
|
ReplaceCallsWithInvalidTypeArgumentForReifiedParameters(context),
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
|
||||||
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
|
|
||||||
|
|
||||||
|
class ReplaceCallsWithInvalidTypeArgumentForReifiedParameters(val context: JsIrBackendContext) : CallsTransformer {
|
||||||
|
override fun transformFunctionAccess(call: IrFunctionAccessExpression, doNotIntrinsify: Boolean): IrExpression {
|
||||||
|
if (!context.errorPolicy.allowErrors) return call
|
||||||
|
|
||||||
|
val function = call.symbol.owner
|
||||||
|
|
||||||
|
for (typeParameter in function.typeParameters) {
|
||||||
|
if (!typeParameter.isReified) continue
|
||||||
|
val typeArgument = call.getTypeArgument(typeParameter.index)
|
||||||
|
|
||||||
|
if (typeArgument?.classOrNull == null) {
|
||||||
|
val args = call.getArgumentsWithIr().map { it.second }
|
||||||
|
|
||||||
|
val callErrorCode = JsIrBuilder.buildCall(context.errorCodeSymbol!!).apply {
|
||||||
|
putValueArgument(
|
||||||
|
0,
|
||||||
|
IrConstImpl.string(
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
context.irBuiltIns.stringType,
|
||||||
|
"Invalid type argument (${typeArgument?.render()}) for reified type parameter (${typeParameter.render()})"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.isEmpty()) return callErrorCode
|
||||||
|
|
||||||
|
return IrCompositeImpl(-1, -1, call.type, call.origin, args + listOf(callErrorCode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// ERROR_POLICY: SEMANTIC
|
||||||
|
|
||||||
|
// MODULE: lib
|
||||||
|
// FILE: t.kt
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
var l = ""
|
||||||
|
fun log(s: String, r: Any? = null): Any? {
|
||||||
|
l += s + ";"
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun assertFails(block: () -> Unit) {
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fail("Expected an exception to be thrown, but was completed successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <reified R> getKClassFromRaifed(b: Boolean): KClass<R>? {
|
||||||
|
log("getKClassFromRaifed($b)")
|
||||||
|
if (b) return R::class
|
||||||
|
log("getKClassFromRaifed: null")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> getKClassFromT(b: Boolean): KClass<T>? {
|
||||||
|
log("getKClassFromT($b)")
|
||||||
|
if (b) return T::class
|
||||||
|
log("getKClassFromT: null")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getKClassFromErrorType(b: Boolean): KClass<*>? {
|
||||||
|
log("getKClassFromErrorType($b)")
|
||||||
|
if (b) return ErrT::class
|
||||||
|
log("getKClassFromErrorType: null")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified R, T> test1() {
|
||||||
|
assertFails { getKClassFromRaifed<R>(true) }
|
||||||
|
assertFails { getKClassFromRaifed<T>(true) }
|
||||||
|
assertFails { getKClassFromRaifed<String>(true) }
|
||||||
|
assertFails { getKClassFromT<R>(true) }
|
||||||
|
assertFails { getKClassFromT<T>(true) }
|
||||||
|
assertFails { getKClassFromT<String>(true) }
|
||||||
|
assertFails { getKClassFromErrorType(true) }
|
||||||
|
getKClassFromRaifed<R>(false)
|
||||||
|
getKClassFromRaifed<T>(false)
|
||||||
|
getKClassFromRaifed<String>(false)
|
||||||
|
getKClassFromT<R>(false)
|
||||||
|
getKClassFromT<T>(false)
|
||||||
|
getKClassFromT<String>(false)
|
||||||
|
getKClassFromErrorType(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified R> foo(a: Any, b: Any, c: Any): KClass<*>? {
|
||||||
|
log("foo")
|
||||||
|
return R::class
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> testSideEffects() {
|
||||||
|
assertFails { foo<T>(log("1", 1), log("2", 2), log("3", 3)) }
|
||||||
|
foo<String>(log("a", 1), log("b", 2), log("c", 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: b.kt
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
test1<Int, Short>()
|
||||||
|
testSideEffects()
|
||||||
|
|
||||||
|
|
||||||
|
val expected = "getKClassFromRaifed(true);getKClassFromRaifed(true);getKClassFromRaifed(true);" +
|
||||||
|
"getKClassFromT(true);getKClassFromT(true);getKClassFromT(true);" +
|
||||||
|
"getKClassFromErrorType(true);" +
|
||||||
|
"getKClassFromRaifed(false);getKClassFromRaifed: null;getKClassFromRaifed(false);getKClassFromRaifed: null;getKClassFromRaifed(false);getKClassFromRaifed: null;" +
|
||||||
|
"getKClassFromT(false);getKClassFromT: null;getKClassFromT(false);getKClassFromT: null;getKClassFromT(false);getKClassFromT: null;" +
|
||||||
|
"getKClassFromErrorType(false);getKClassFromErrorType: null;" +
|
||||||
|
"1;2;3;foo;a;b;c;foo;"
|
||||||
|
|
||||||
|
if (l != expected)
|
||||||
|
return "l = $l"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+5
@@ -72,6 +72,11 @@ public class IrJsCodegenBoxErrorTestGenerated extends AbstractIrJsCodegenBoxErro
|
|||||||
runTest("compiler/testData/codegen/boxError/semantic/reifiedNonInline.kt");
|
runTest("compiler/testData/codegen/boxError/semantic/reifiedNonInline.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedWithWrongArguments.kt")
|
||||||
|
public void testReifiedWithWrongArguments() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/boxError/semantic/reifiedWithWrongArguments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("typeMismatch.kt")
|
@TestMetadata("typeMismatch.kt")
|
||||||
public void testTypeMismatch() throws Exception {
|
public void testTypeMismatch() throws Exception {
|
||||||
runTest("compiler/testData/codegen/boxError/semantic/typeMismatch.kt");
|
runTest("compiler/testData/codegen/boxError/semantic/typeMismatch.kt");
|
||||||
|
|||||||
@@ -5,4 +5,4 @@
|
|||||||
|
|
||||||
package kotlin.js
|
package kotlin.js
|
||||||
|
|
||||||
internal external fun <T : Any> jsClass(): JsClass<T>
|
internal inline fun <reified T : Any> jsClass(): JsClass<T> = throw NotImplementedError("Implemented as intrinsic")
|
||||||
|
|||||||
Reference in New Issue
Block a user