[JS IR BE] Bridges construction
This commit is contained in:
@@ -89,6 +89,7 @@ fun JsIrBackendContext.lower(file: IrFile) {
|
||||
PropertiesLowering().lower(file)
|
||||
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
|
||||
MultipleCatchesLowering(this).lower(file)
|
||||
BridgesConstruction(this).runOnFilePostfix(file)
|
||||
TypeOperatorLowering(this).lower(file)
|
||||
BlockDecomposerLowering(this).runOnFilePostfix(file)
|
||||
SecondaryCtorLowering(this).runOnFilePostfix(file)
|
||||
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge
|
||||
import org.jetbrains.kotlin.backend.common.bridges.FunctionHandle
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridges
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.isStatic
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.isReal
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
// Constructs bridges for inherited generic functions
|
||||
//
|
||||
// Example: for given class hierarchy
|
||||
//
|
||||
// class C<T> {
|
||||
// fun foo(t: T) = ...
|
||||
// }
|
||||
//
|
||||
// class D : C<Int> {
|
||||
// override fun foo(t: Int) = impl
|
||||
// }
|
||||
//
|
||||
// it adds method D that delegates generic calls to implementation:
|
||||
//
|
||||
// class D : C<Int> {
|
||||
// override fun foo(t: Int) = impl
|
||||
// fun foo(t: Any?) = foo(t as Int) // Constructed bridge
|
||||
// }
|
||||
//
|
||||
class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
irClass.declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.filter { !it.isStatic }
|
||||
.forEach { generateBridges(it, irClass) }
|
||||
|
||||
irClass.declarations
|
||||
.filterIsInstance<IrProperty>()
|
||||
.flatMap { listOfNotNull(it.getter, it.setter) }
|
||||
.forEach { generateBridges(it, irClass) }
|
||||
}
|
||||
|
||||
private fun generateBridges(function: IrSimpleFunction, irClass: IrClass) {
|
||||
// equals(Any?), hashCode(), toString() never need bridges
|
||||
if (DescriptorUtils.isMethodOfAny(function.descriptor))
|
||||
return
|
||||
|
||||
val bridgesToGenerate = generateBridges(
|
||||
function = IrBasedFunctionHandle(function),
|
||||
signature = { FunctionAndSignature(it.function) }
|
||||
)
|
||||
|
||||
for ((from, to) in bridgesToGenerate) {
|
||||
if (to.function.visibility == Visibilities.INVISIBLE_FAKE)
|
||||
continue
|
||||
|
||||
if (!from.function.parentAsClass.isInterface &&
|
||||
from.function.isReal &&
|
||||
from.function.modality != Modality.ABSTRACT &&
|
||||
!to.function.isReal
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
irClass.declarations.add(createBridge(function, from.function, to.function))
|
||||
}
|
||||
}
|
||||
|
||||
// Ported from from jvm.lower.BridgeLowering
|
||||
private fun createBridge(
|
||||
function: IrSimpleFunction,
|
||||
bridge: IrSimpleFunction,
|
||||
delegateTo: IrSimpleFunction
|
||||
): IrFunction {
|
||||
val containingClass = function.parentAsClass.descriptor
|
||||
|
||||
val bridgeDescriptorForIrFunction = SimpleFunctionDescriptorImpl.create(
|
||||
containingClass,
|
||||
Annotations.EMPTY,
|
||||
bridge.name,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
function.descriptor.source)
|
||||
|
||||
// TODO: should copy modality
|
||||
bridgeDescriptorForIrFunction.initialize(
|
||||
bridge.descriptor.extensionReceiverParameter?.returnType, containingClass.thisAsReceiverParameter,
|
||||
bridge.descriptor.typeParameters,
|
||||
bridge.descriptor.valueParameters.map { it.copy(bridgeDescriptorForIrFunction, it.name, it.index) },
|
||||
bridge.descriptor.returnType, Modality.OPEN, function.visibility
|
||||
)
|
||||
|
||||
// TODO: Support offsets for debug info
|
||||
val irFunction = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, bridgeDescriptorForIrFunction)
|
||||
irFunction.createParameterDeclarations()
|
||||
|
||||
// TODO: Add type casts
|
||||
context.createIrBuilder(irFunction.symbol).irBlockBody(irFunction) {
|
||||
val call = irCall(delegateTo.symbol)
|
||||
call.dispatchReceiver = irGet(irFunction.dispatchReceiverParameter!!)
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
call.extensionReceiver = irGet(it)
|
||||
}
|
||||
irFunction.valueParameters.mapIndexed { i, valueParameter ->
|
||||
call.putValueArgument(i, irGet(valueParameter))
|
||||
}
|
||||
+irReturn(call)
|
||||
}.apply {
|
||||
irFunction.body = this
|
||||
}
|
||||
|
||||
return irFunction
|
||||
}
|
||||
}
|
||||
|
||||
// Handle for common.bridges
|
||||
data class IrBasedFunctionHandle(val function: IrSimpleFunction) : FunctionHandle {
|
||||
|
||||
override val isDeclaration: Boolean = true
|
||||
|
||||
override val isAbstract: Boolean =
|
||||
function.modality == Modality.ABSTRACT
|
||||
|
||||
override val isInterfaceDeclaration=
|
||||
function.parentAsClass.isInterface
|
||||
|
||||
override fun getOverridden()=
|
||||
function.overriddenSymbols.map { IrBasedFunctionHandle(it.owner) }
|
||||
}
|
||||
|
||||
// Wrapper around function that compares and hashCodes it based on signature
|
||||
// Designed to be used as a Signature type parameter in backend.common.bridges
|
||||
class FunctionAndSignature(val function: IrSimpleFunction) {
|
||||
|
||||
// TODO: Use type-upper-bound-based signature instead of Strings
|
||||
// Currently strings are used for compatibility with a hack-based name generator
|
||||
|
||||
private data class Signature(
|
||||
val name: Name,
|
||||
val extensionReceiverType: String?,
|
||||
val valueParameters: List<String?>
|
||||
)
|
||||
|
||||
private val signature = Signature(
|
||||
function.name,
|
||||
function.extensionReceiverParameter?.type?.toKotlinType()?.toString(),
|
||||
function.valueParameters.map { it.type.toKotlinType()?.toString() }
|
||||
)
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
signature == (other as FunctionAndSignature).signature
|
||||
|
||||
override fun hashCode(): Int = signature.hashCode()
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,5 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
|
||||
interface JvmLoweredStatementOrigin : IrStatementOrigin {
|
||||
object DEFAULT_IMPLS_DELEGATION : IrStatementOriginImpl("DEFAULT_IMPL_DELEGATION")
|
||||
object BRIDGE_DELEGATION : IrStatementOriginImpl("BRIDGE_DELEGATION")
|
||||
object TO_ARRAY : IrDeclarationOriginImpl("TO_ARRAY")
|
||||
}
|
||||
+6
-6
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.irNot
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.DefaultImplsClassDescriptor
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.isAbstractMethod
|
||||
@@ -37,6 +36,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
@@ -219,7 +219,7 @@ class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
implementation.returnType!!.toIrType()!!,
|
||||
implementation,
|
||||
implementation.typeParametersCount,
|
||||
JvmLoweredStatementOrigin.BRIDGE_DELEGATION,
|
||||
IrStatementOrigin.BRIDGE_DELEGATION,
|
||||
if (isStubDeclarationWithDelegationToSuper) getSuperClassDescriptor(
|
||||
descriptor.containingDeclaration as ClassDescriptor
|
||||
) else null
|
||||
@@ -228,14 +228,14 @@ class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
irFunction.dispatchReceiverParameter!!.symbol,
|
||||
JvmLoweredStatementOrigin.BRIDGE_DELEGATION
|
||||
IrStatementOrigin.BRIDGE_DELEGATION
|
||||
)
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
call.extensionReceiver = IrGetValueImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
it.symbol,
|
||||
JvmLoweredStatementOrigin.BRIDGE_DELEGATION
|
||||
IrStatementOrigin.BRIDGE_DELEGATION
|
||||
)
|
||||
}
|
||||
irFunction.valueParameters.mapIndexed { i, valueParameter ->
|
||||
@@ -245,7 +245,7 @@ class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
valueParameter.symbol,
|
||||
JvmLoweredStatementOrigin.BRIDGE_DELEGATION
|
||||
IrStatementOrigin.BRIDGE_DELEGATION
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -279,7 +279,7 @@ class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
bridgeFunction.valueParameters[i].symbol,
|
||||
JvmLoweredStatementOrigin.BRIDGE_DELEGATION
|
||||
IrStatementOrigin.BRIDGE_DELEGATION
|
||||
)
|
||||
if (delegateParameterTypes == null || OBJECT_TYPE == delegateParameterTypes[i]) {
|
||||
irNotEquals(checkValue, irNull())
|
||||
|
||||
@@ -93,6 +93,8 @@ interface IrStatementOrigin {
|
||||
|
||||
object PROPERTY_REFERENCE_FOR_DELEGATE : IrStatementOriginImpl("PROPERTY_REFERENCE_FOR_DELEGATE")
|
||||
|
||||
object BRIDGE_DELEGATION : IrStatementOriginImpl("BRIDGE_DELEGATION")
|
||||
|
||||
data class COMPONENT_N private constructor(val index: Int) : IrStatementOriginImpl("COMPONENT_$index") {
|
||||
companion object {
|
||||
private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) }
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T, U> {
|
||||
fun foo(t: T, u: U) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// KT-3985
|
||||
|
||||
interface Trait<T> {
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T> {
|
||||
fun foo(t: T): String
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T> {
|
||||
fun foo(t: T, u: Int) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T> {
|
||||
open fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T, U, V> {
|
||||
open fun foo(t: T, u: U, v: V) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T, U> {
|
||||
fun foo(t: T, u: U) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T> {
|
||||
open fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T> {
|
||||
open fun <U> foo(t: T, u: U) = "A"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T> {
|
||||
open fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T> {
|
||||
fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T : Number> {
|
||||
open fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
abstract class A<T> {
|
||||
abstract fun foo(t: T): String
|
||||
}
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T : U, U> {
|
||||
open fun foo(t: T, u: U) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T> {
|
||||
fun id(t: T): T
|
||||
}
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
public open class A<T> {
|
||||
fun foo(x: T) = "O"
|
||||
fun foo(x: A<T>) = "K"
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T> {
|
||||
open fun <U> foo(t: T, u: U) = "A"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T> {
|
||||
open fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T> {
|
||||
open fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
open class A<T : Number> {
|
||||
open fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T> {
|
||||
fun foo(t: T, u: Int) = "A"
|
||||
}
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T> {
|
||||
fun foo(t: T, u: Int) = "A"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T> {
|
||||
fun foo(t: T) = "A"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T> {
|
||||
fun foo(t: T): String
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
interface A<T: Number> {
|
||||
fun foo(t: T): String
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
var GUEST_USER_ID = 3
|
||||
val USER_ID =
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
class A {
|
||||
fun foo() {}
|
||||
fun bar(f: A.() -> Unit = {}) {}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
abstract class A<T> {
|
||||
abstract fun test(a: T, b:Boolean = false) : String
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
fun unsupportedEx() {
|
||||
if (true) throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
fun unsupportedEx() {
|
||||
if (true) throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
package org.example
|
||||
|
||||
interface SomeTrait {}
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
class A(
|
||||
val a: String = {
|
||||
open class B() {
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
var global = 0
|
||||
|
||||
fun sideEffect() = global++
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isAny;
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.*;
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns;
|
||||
|
||||
@@ -634,4 +635,15 @@ public class DescriptorUtils {
|
||||
: descriptor;
|
||||
}
|
||||
|
||||
public static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) {
|
||||
String name = descriptor.getName().asString();
|
||||
List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
|
||||
if (parameters.isEmpty()) {
|
||||
return name.equals("hashCode") || name.equals("toString");
|
||||
}
|
||||
else if (parameters.size() == 1 && name.equals("equals")) {
|
||||
return isNullableAny(parameters.get(0).getType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1118
|
||||
// This test was adapted from compiler/testData/codegen/box/classes
|
||||
package foo
|
||||
|
||||
@@ -49,6 +49,11 @@ open class AssertionError(message: String?, cause: Throwable?) : Exception(messa
|
||||
|
||||
}
|
||||
|
||||
open class UnsupportedOperationException(message: String?, cause: Throwable?) : RuntimeException(message, cause) {
|
||||
constructor() : this(null, null)
|
||||
constructor(message: String?) : this(message, null)
|
||||
constructor(cause: Throwable?) : this(null, cause)
|
||||
}
|
||||
|
||||
// TODO: fix function names to satisfy style convention (depends on built-in names)
|
||||
fun THROW_CCE() {
|
||||
|
||||
Reference in New Issue
Block a user