JS/RTTI: support unsafe casts
#KT-2670 fixed
This commit is contained in:
committed by
Alexey Andreev
parent
1d2da9729e
commit
3fd387d4a6
+2
@@ -36,6 +36,8 @@ var JsFunction.isLocal: Boolean by MetadataProperty(default = false)
|
|||||||
|
|
||||||
var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false)
|
var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false)
|
||||||
|
|
||||||
|
var JsConditional.isUnsafeCast: Boolean by MetadataProperty(default = false)
|
||||||
|
|
||||||
var JsInvocation.typeCheck: TypeCheck? by MetadataProperty(default = null)
|
var JsInvocation.typeCheck: TypeCheck? by MetadataProperty(default = null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ public class NumberFormatException(message: String? = null) : RuntimeException(m
|
|||||||
@library
|
@library
|
||||||
public class NullPointerException(message: String? = null) : RuntimeException(message) {}
|
public class NullPointerException(message: String? = null) : RuntimeException(message) {}
|
||||||
|
|
||||||
|
library
|
||||||
|
public class ClassCastException(message: String? = null) : RuntimeException(message) {}
|
||||||
|
|
||||||
@library
|
@library
|
||||||
public class AssertionError(message: String? = null) : Error(message) {}
|
public class AssertionError(message: String? = null) : Error(message) {}
|
||||||
|
|
||||||
|
|||||||
@@ -41,15 +41,27 @@ public class CastTestGenerated extends AbstractCastTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("castToNotNullType.kt")
|
@TestMetadata("castToNotNull.kt")
|
||||||
public void testCastToNotNullType() throws Exception {
|
public void testCastToNotNull() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToNotNullType.kt");
|
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToNotNull.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("castToNullableType.kt")
|
@TestMetadata("castToNullable.kt")
|
||||||
public void testCastToNullableType() throws Exception {
|
public void testCastToNullable() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToNullableType.kt");
|
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToNullable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedToNotNull.kt")
|
||||||
|
public void testReifiedToNotNull() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/reifiedToNotNull.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedToNullable.kt")
|
||||||
|
public void testReifiedToNullable() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/reifiedToNullable.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,22 @@ public class DirectiveTestUtils {
|
|||||||
|
|
||||||
private static final DirectiveHandler COUNT_NULLS = new CountNodesDirective<JsNullLiteral>("CHECK_NULLS_COUNT", JsNullLiteral.class);
|
private static final DirectiveHandler COUNT_NULLS = new CountNodesDirective<JsNullLiteral>("CHECK_NULLS_COUNT", JsNullLiteral.class);
|
||||||
|
|
||||||
|
private static final DirectiveHandler NOT_REFERENCED = new DirectiveHandler("CHECK_NOT_REFERENCED") {
|
||||||
|
@Override
|
||||||
|
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
||||||
|
final String reference = arguments.getPositionalArgument(0);
|
||||||
|
|
||||||
|
JsVisitor visitor = new RecursiveJsVisitor() {
|
||||||
|
@Override
|
||||||
|
public void visitNameRef(@NotNull JsNameRef nameRef) {
|
||||||
|
assertNotEquals(reference, nameRef.toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
visitor.accept(ast);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private static final DirectiveHandler HAS_INLINE_METADATA = new DirectiveHandler("CHECK_HAS_INLINE_METADATA") {
|
private static final DirectiveHandler HAS_INLINE_METADATA = new DirectiveHandler("CHECK_HAS_INLINE_METADATA") {
|
||||||
@Override
|
@Override
|
||||||
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
||||||
@@ -178,6 +194,7 @@ public class DirectiveTestUtils {
|
|||||||
COUNT_VARS,
|
COUNT_VARS,
|
||||||
COUNT_BREAKS,
|
COUNT_BREAKS,
|
||||||
COUNT_NULLS,
|
COUNT_NULLS,
|
||||||
|
NOT_REFERENCED,
|
||||||
HAS_INLINE_METADATA,
|
HAS_INLINE_METADATA,
|
||||||
HAS_NO_INLINE_METADATA
|
HAS_NO_INLINE_METADATA
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ public final class Namer {
|
|||||||
public static final String ANOTHER_THIS_PARAMETER_NAME = "$this";
|
public static final String ANOTHER_THIS_PARAMETER_NAME = "$this";
|
||||||
|
|
||||||
private static final String THROW_NPE_FUN_NAME = "throwNPE";
|
private static final String THROW_NPE_FUN_NAME = "throwNPE";
|
||||||
|
private static final String THROW_CLASS_CAST_EXCEPTION_FUN_NAME = "throwCCE";
|
||||||
private static final String PROTOTYPE_NAME = "prototype";
|
private static final String PROTOTYPE_NAME = "prototype";
|
||||||
private static final String CAPTURED_VAR_FIELD = "v";
|
private static final String CAPTURED_VAR_FIELD = "v";
|
||||||
|
|
||||||
@@ -363,6 +364,11 @@ public final class Namer {
|
|||||||
return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
|
return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JsExpression throwClassCastExceptionFunRef() {
|
||||||
|
return new JsNameRef(THROW_CLASS_CAST_EXCEPTION_FUN_NAME, kotlinObject());
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsNameRef kotlin(@NotNull JsName name) {
|
public static JsNameRef kotlin(@NotNull JsName name) {
|
||||||
return fqnWithoutSideEffects(name, kotlinObject());
|
return fqnWithoutSideEffects(name, kotlinObject());
|
||||||
|
|||||||
+11
-18
@@ -36,8 +36,6 @@ import org.jetbrains.kotlin.js.translate.operation.UnaryOperationTranslator;
|
|||||||
import org.jetbrains.kotlin.js.translate.reference.*;
|
import org.jetbrains.kotlin.js.translate.reference.*;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||||
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.lexer.KtTokens;
|
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
|
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
@@ -392,25 +390,20 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public JsNode visitBinaryWithTypeRHSExpression(@NotNull KtBinaryExpressionWithTypeRHS expression,
|
public JsNode visitBinaryWithTypeRHSExpression(
|
||||||
@NotNull TranslationContext context) {
|
@NotNull KtBinaryExpressionWithTypeRHS expression,
|
||||||
JsExpression jsExpression = Translation.translateAsExpression(expression.getLeft(), context);
|
@NotNull TranslationContext context
|
||||||
|
) {
|
||||||
|
JsExpression jsExpression;
|
||||||
|
|
||||||
if (expression.getOperationReference().getReferencedNameElementType() != KtTokens.AS_KEYWORD)
|
if (PatternTranslator.isUnsafeCast(expression)) {
|
||||||
return jsExpression.source(expression);
|
jsExpression = PatternTranslator.newInstance(context).translateUnsafeCast(expression);
|
||||||
|
}
|
||||||
KtTypeReference right = expression.getRight();
|
else {
|
||||||
assert right != null;
|
jsExpression = Translation.translateAsExpression(expression.getLeft(), context);
|
||||||
|
|
||||||
KotlinType rightType = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.TYPE, right);
|
|
||||||
KotlinType leftType = BindingContextUtils.getTypeNotNull(context.bindingContext(), expression.getLeft());
|
|
||||||
if (TypeUtils.isNullableType(rightType) || !TypeUtils.isNullableType(leftType)) {
|
|
||||||
return jsExpression.source(expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// KT-2670
|
return jsExpression.source(expression);
|
||||||
// we actually do not care for types in js
|
|
||||||
return TranslationUtils.sure(jsExpression, context).source(expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getReferencedName(KtSimpleNameExpression expression) {
|
private static String getReferencedName(KtSimpleNameExpression expression) {
|
||||||
|
|||||||
+29
-1
@@ -16,20 +16,25 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.translate.expression;
|
package org.jetbrains.kotlin.js.translate.expression;
|
||||||
|
|
||||||
|
import com.google.dart.compiler.backend.js.ast.JsConditional;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsInvocation;
|
import com.google.dart.compiler.backend.js.ast.JsInvocation;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||||
|
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.js.patterns.NamePredicate;
|
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt;
|
||||||
|
import org.jetbrains.kotlin.js.patterns.NamePredicate;
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer;
|
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
|
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS;
|
||||||
import org.jetbrains.kotlin.psi.KtExpression;
|
import org.jetbrains.kotlin.psi.KtExpression;
|
||||||
import org.jetbrains.kotlin.psi.KtIsExpression;
|
import org.jetbrains.kotlin.psi.KtIsExpression;
|
||||||
import org.jetbrains.kotlin.psi.KtTypeReference;
|
import org.jetbrains.kotlin.psi.KtTypeReference;
|
||||||
@@ -50,6 +55,29 @@ public final class PatternTranslator extends AbstractTranslator {
|
|||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isUnsafeCast(@NotNull KtBinaryExpressionWithTypeRHS expression) {
|
||||||
|
return expression.getOperationReference().getReferencedNameElementType() == KtTokens.AS_KEYWORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JsExpression translateUnsafeCast(@NotNull KtBinaryExpressionWithTypeRHS expression) {
|
||||||
|
assert isUnsafeCast(expression): "Expected unsafe cast expression, got " + expression;
|
||||||
|
KtExpression left = expression.getLeft();
|
||||||
|
JsExpression expressionToCast = Translation.translateAsExpression(left, context());
|
||||||
|
TemporaryVariable temporary = context().declareTemporary(expressionToCast);
|
||||||
|
|
||||||
|
KtTypeReference typeReference = expression.getRight();
|
||||||
|
assert typeReference != null: "Unsafe cast must have type reference";
|
||||||
|
JsExpression isCheck = translateIsCheck(temporary.assignmentExpression(), typeReference);
|
||||||
|
|
||||||
|
Namer namer = context().namer();
|
||||||
|
JsExpression throwCCEFunRef = namer.throwClassCastExceptionFunRef();
|
||||||
|
JsExpression throwCCE = new JsInvocation(throwCCEFunRef);
|
||||||
|
JsConditional conditional = new JsConditional(isCheck, temporary.reference(), throwCCE);
|
||||||
|
MetadataProperties.setUnsafeCast(conditional, true);
|
||||||
|
return conditional;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JsExpression translateIsExpression(@NotNull KtIsExpression expression) {
|
public JsExpression translateIsExpression(@NotNull KtIsExpression expression) {
|
||||||
JsExpression left = Translation.translateAsExpression(expression.getLeftHandSide(), context());
|
JsExpression left = Translation.translateAsExpression(expression.getLeftHandSide(), context());
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.translate.utils
|
|||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck
|
import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck
|
||||||
|
import com.google.dart.compiler.backend.js.ast.metadata.isUnsafeCast
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.typeCheck
|
import com.google.dart.compiler.backend.js.ast.metadata.typeCheck
|
||||||
import org.jetbrains.kotlin.js.inline.util.IdentitySet
|
import org.jetbrains.kotlin.js.inline.util.IdentitySet
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
@@ -50,6 +51,17 @@ private class TypeCheckRewritingVisitor(private val context: TranslationContext)
|
|||||||
super.endVisit(x, ctx)
|
super.endVisit(x, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun endVisit(x: JsConditional, ctx: JsContext<JsNode>) {
|
||||||
|
val test = x.testExpression
|
||||||
|
|
||||||
|
if (x.isUnsafeCast &&
|
||||||
|
test is JsBinaryOperation &&
|
||||||
|
test.operator == JsBinaryOperator.ASG
|
||||||
|
) {
|
||||||
|
ctx.replaceMe(test.arg2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visit(x: JsInvocation, ctx: JsContext<JsNode>): Boolean {
|
override fun visit(x: JsInvocation, ctx: JsContext<JsNode>): Boolean {
|
||||||
// callee(calleeArgument)(argument)
|
// callee(calleeArgument)(argument)
|
||||||
val callee = x.qualifier as? JsInvocation
|
val callee = x.qualifier as? JsInvocation
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package kotlin
|
||||||
|
|
||||||
|
// CHECK_NOT_REFERENCED: Kotlin.isInstanceOf
|
||||||
|
// CHECK_NOT_REFERENCED: Kotlin.isTypeOf
|
||||||
|
// CHECK_NOT_REFERENCED: Kotlin.orNull
|
||||||
|
|
||||||
|
fun failsClassCast(message: String, fn: ()->Unit) {
|
||||||
|
try {
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
catch (e: ClassCastException) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception("Expected ClassCastException to be thrown: message=$message")
|
||||||
|
}
|
||||||
@@ -43,17 +43,6 @@ fun test(f: () -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fails(f: () -> Unit) {
|
|
||||||
try {
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
catch(e: Exception) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Exception("Expected an exception to be thrown from $f")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val a = A("OK")
|
val a = A("OK")
|
||||||
|
|
||||||
@@ -69,6 +58,7 @@ fun box(): String {
|
|||||||
|
|
||||||
test { castNullableToNotNullT<A>(a) }
|
test { castNullableToNotNullT<A>(a) }
|
||||||
fails { castNullableToNotNullT<A>(null) }
|
fails { castNullableToNotNullT<A>(null) }
|
||||||
|
failsClassCast("castNullableToNotNullT<A>(null)") { castNullableToNotNullT<A>(null) }
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
trait A
|
||||||
|
|
||||||
|
class AImpl: A
|
||||||
|
|
||||||
|
fun test(x: Any?): A = x as A
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var a: A = AImpl()
|
||||||
|
assertEquals(a, test(a), "a = AImpl()")
|
||||||
|
a = object : A {}
|
||||||
|
assertEquals(a, test(a), "a = object : A{}")
|
||||||
|
failsClassCast("test(null)") { test(null) }
|
||||||
|
failsClassCast("test(object{})") { test(object{}) }
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package foo
|
|
||||||
|
|
||||||
class A
|
|
||||||
|
|
||||||
fun checkCastNullableToNotNull(): Boolean {
|
|
||||||
val a = null
|
|
||||||
try {
|
|
||||||
val s = a as A
|
|
||||||
}
|
|
||||||
catch (e: Exception) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun checkCastNotNullToNotNull(): Boolean {
|
|
||||||
val a = A()
|
|
||||||
var s = a as A
|
|
||||||
return s == a
|
|
||||||
}
|
|
||||||
|
|
||||||
fun box(): String {
|
|
||||||
if (!checkCastNullableToNotNull()) return "Failed when try cast Nullable to NotNull"
|
|
||||||
if (!checkCastNotNullToNotNull()) return "Failed when try cast NotNull to NotNull"
|
|
||||||
return "OK"
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
interface A
|
||||||
|
|
||||||
|
class AImpl : A {}
|
||||||
|
|
||||||
|
fun test(x: Any?): A? = x as A?
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var a: A? = AImpl()
|
||||||
|
assertEquals(a, test(a), "a = AImpl()")
|
||||||
|
a = object : A {}
|
||||||
|
assertEquals(a, test(a), "a = object : A{}")
|
||||||
|
assertEquals(null, test(null), "test(null)")
|
||||||
|
failsClassCast("test(object{})") { test(object{}) }
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package foo
|
|
||||||
|
|
||||||
class A
|
|
||||||
|
|
||||||
fun <T> Any.cast() = this!! as T
|
|
||||||
|
|
||||||
fun box(): String {
|
|
||||||
val a = null
|
|
||||||
val s = a as A?
|
|
||||||
if (s != null) return "Failed when try cast Nullable with null value to Nullable"
|
|
||||||
|
|
||||||
val b: A? = A()
|
|
||||||
val n = b as A?
|
|
||||||
if (n != b) return "Failed when try cast Nullable with not null value to Nullable"
|
|
||||||
|
|
||||||
val c = A()
|
|
||||||
val m = c as A?
|
|
||||||
if (m != c) return "Failed when try cast NotNull to Nullable"
|
|
||||||
|
|
||||||
return "OK"
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
// CHECK_NOT_CALLED: test
|
||||||
|
|
||||||
|
trait A
|
||||||
|
|
||||||
|
class AImpl: A
|
||||||
|
|
||||||
|
inline
|
||||||
|
fun test<reified T>(x: Any?): T = x as T
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var a: A = AImpl()
|
||||||
|
assertEquals(a, test<A>(a), "a = AImpl()")
|
||||||
|
a = object : A {}
|
||||||
|
assertEquals(a, test<A>(a), "a = object : A{}")
|
||||||
|
failsClassCast("test(null)") { test<A>(null) }
|
||||||
|
failsClassCast("test(object{})") { test<A>(object{}) }
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
interface A
|
||||||
|
|
||||||
|
class AImpl : A {}
|
||||||
|
|
||||||
|
inline
|
||||||
|
fun test<reified T>(x: Any?): T = x as T
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var a: A? = AImpl()
|
||||||
|
assertEquals(a, test<A?>(a), "a = AImpl()")
|
||||||
|
a = object : A {}
|
||||||
|
assertEquals(a, test<A?>(a), "a = object : A{}")
|
||||||
|
assertEquals(null, test<A?>(null), "test(null)")
|
||||||
|
failsClassCast("test(object{})") { test<A?>(object{}) }
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+5
@@ -199,6 +199,7 @@
|
|||||||
Kotlin.IllegalStateException = createClassNowWithMessage(Kotlin.RuntimeException);
|
Kotlin.IllegalStateException = createClassNowWithMessage(Kotlin.RuntimeException);
|
||||||
Kotlin.UnsupportedOperationException = createClassNowWithMessage(Kotlin.RuntimeException);
|
Kotlin.UnsupportedOperationException = createClassNowWithMessage(Kotlin.RuntimeException);
|
||||||
Kotlin.IndexOutOfBoundsException = createClassNowWithMessage(Kotlin.RuntimeException);
|
Kotlin.IndexOutOfBoundsException = createClassNowWithMessage(Kotlin.RuntimeException);
|
||||||
|
Kotlin.ClassCastException = createClassNowWithMessage(Kotlin.RuntimeException);
|
||||||
Kotlin.IOException = createClassNowWithMessage(Kotlin.Exception);
|
Kotlin.IOException = createClassNowWithMessage(Kotlin.Exception);
|
||||||
Kotlin.AssertionError = createClassNowWithMessage(Kotlin.Error);
|
Kotlin.AssertionError = createClassNowWithMessage(Kotlin.Error);
|
||||||
|
|
||||||
@@ -206,6 +207,10 @@
|
|||||||
throw new Kotlin.NullPointerException(message);
|
throw new Kotlin.NullPointerException(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Kotlin.throwCCE = function () {
|
||||||
|
throw new Kotlin.ClassCastException("Illegal cast");
|
||||||
|
};
|
||||||
|
|
||||||
function throwAbstractFunctionInvocationError(funName) {
|
function throwAbstractFunctionInvocationError(funName) {
|
||||||
return function () {
|
return function () {
|
||||||
var message;
|
var message;
|
||||||
|
|||||||
Reference in New Issue
Block a user