diff --git a/plugins/java-model-wrappers/java-model-wrappers.iml b/plugins/java-model-wrappers/java-model-wrappers.iml
index 3ebc8d39248..bd0c3feaf10 100755
--- a/plugins/java-model-wrappers/java-model-wrappers.iml
+++ b/plugins/java-model-wrappers/java-model-wrappers.iml
@@ -8,7 +8,6 @@
-
diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/JeAnnotationOwner.kt b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/JeAnnotationOwner.kt
index 7adb4e02233..ce620704039 100644
--- a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/JeAnnotationOwner.kt
+++ b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/JeAnnotationOwner.kt
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.java.model
import com.intellij.psi.PsiAnnotationOwner
import com.intellij.psi.PsiClass
import org.jetbrains.kotlin.java.model.elements.JeAnnotationMirror
-import org.jetbrains.kotlin.java.model.internal.createAnnotation
+import org.jetbrains.kotlin.java.model.internal.KotlinAnnotationProxyMaker
import javax.lang.model.element.AnnotationMirror
import javax.lang.model.element.Element
import java.lang.reflect.Array as RArray
@@ -30,14 +30,18 @@ interface JeAnnotationOwner : Element {
override fun getAnnotationMirrors() = annotationOwner?.annotations?.map { JeAnnotationMirror(it) } ?: emptyList()
override fun getAnnotation(annotationClass: Class): A? {
+ if (!annotationClass.isAnnotation) {
+ throw IllegalArgumentException("Not an annotation class: " + annotationClass)
+ }
+
val annotationFqName = annotationClass.canonicalName
val annotation = annotationOwner?.annotations
?.firstOrNull { it.qualifiedName == annotationFqName } ?: return null
val annotationDeclaration = annotation.nameReferenceElement?.resolve() as? PsiClass ?: return null
-
+
@Suppress("UNCHECKED_CAST")
- return createAnnotation(annotation, annotationDeclaration, annotationClass) as? A
+ return KotlinAnnotationProxyMaker(annotation, annotationDeclaration, annotationClass).generate() as? A
}
@Suppress("UNCHECKED_CAST")
diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/AnnotationUtil.java b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/AnnotationUtil.java
new file mode 100644
index 00000000000..4708dbb81f7
--- /dev/null
+++ b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/AnnotationUtil.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2016 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.java.model.internal;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiType;
+import sun.reflect.annotation.EnumConstantNotPresentExceptionProxy;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public final class AnnotationUtil {
+ public static final Map> ARRAY_TYPES_MAP;
+
+ static {
+ Map> classes = new HashMap>();
+
+ classes.put(PsiType.BYTE, byte.class);
+ classes.put(PsiType.SHORT, short.class);
+ classes.put(PsiType.INT, int.class);
+ classes.put(PsiType.CHAR, char.class);
+ classes.put(PsiType.BOOLEAN, boolean.class);
+ classes.put(PsiType.LONG, long.class);
+ classes.put(PsiType.FLOAT, float.class);
+ classes.put(PsiType.DOUBLE, double.class);
+
+ ARRAY_TYPES_MAP = Collections.unmodifiableMap(classes);
+ }
+
+ public static Object createEnumValue(Class> enumClass, String name) {
+ try {
+ return Enum.valueOf((Class)enumClass, name);
+ } catch (IllegalArgumentException ex) {
+ //noinspection unchecked
+ return new EnumConstantNotPresentExceptionProxy((Class>) enumClass, name);
+ }
+
+ }
+}
diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/KotlinAnnotationProxyMaker.kt b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/KotlinAnnotationProxyMaker.kt
new file mode 100644
index 00000000000..8626c0d28ef
--- /dev/null
+++ b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/KotlinAnnotationProxyMaker.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2010-2016 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.java.model.internal
+
+import com.intellij.psi.*
+import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
+import org.jetbrains.kotlin.java.model.types.toJeType
+import sun.reflect.annotation.AnnotationParser
+import sun.reflect.annotation.ExceptionProxy
+import java.io.ObjectInputStream
+import java.lang.reflect.Array
+import java.lang.reflect.Method
+import java.util.*
+import javax.lang.model.type.MirroredTypeException
+import javax.lang.model.type.MirroredTypesException
+import javax.lang.model.type.TypeMirror
+
+class KotlinAnnotationProxyMaker(val annotation: PsiAnnotation, val annotationClass: PsiClass, val annotationType: Class) {
+ fun generate(): Any {
+ return AnnotationParser.annotationForMap(annotationType, getAllValuesForParser(getAllPsiValues()))
+ }
+
+ private fun getAllPsiValues(): List> {
+ val values = mutableListOf>()
+ for (method in annotationClass.methods) {
+ val jMethod = try { annotationType.getMethod(method.name) } catch (e : NoSuchMethodException) { continue }
+ if (method !is PsiAnnotationMethod) continue
+ if (method.returnType == null) continue
+
+ val value = annotation.findAttributeValue(method.name) ?: method.defaultValue ?: continue
+ values += Triple(method, value, jMethod)
+ }
+ return values
+ }
+
+ private fun getAllValuesForParser(values: List>): Map {
+ val parserValues = mutableMapOf()
+ val evaluator = JavaPsiFacade.getInstance(annotation.project).constantEvaluationHelper
+ for ((method, value, jMethod) in values) {
+ val jReturnType = jMethod.returnType ?: unexpectedType("no return type for ${jMethod.name}")
+ parserValues.put(method.name, getConstantValue(value, method.returnType!!, jReturnType, evaluator))
+ }
+ return parserValues
+ }
+}
+
+private fun getConstantValue(
+ psiValue: PsiAnnotationMemberValue,
+ returnType: PsiType,
+ jReturnType: Class<*>,
+ evaluator: PsiConstantEvaluationHelper
+): Any? {
+ val manager = psiValue.manager
+
+ when {
+ returnType == PsiType.NULL || returnType == PsiType.VOID -> unexpectedType("void")
+ jReturnType == String::class.java -> return calculateConstantValue(psiValue, evaluator)
+ jReturnType == Class::class.java -> {
+ val type = (psiValue as PsiClassObjectAccessExpression).operand.type.toJeType(manager)
+ return MirroredTypeExceptionProxy(type)
+ }
+ jReturnType.isArray -> {
+ val jComponentType = jReturnType.componentType ?: unexpectedType("no component type for $jReturnType")
+ if (returnType !is PsiArrayType) unexpectedType(returnType)
+
+ val arrayValues = when (psiValue) {
+ is PsiArrayInitializerMemberValue -> psiValue.initializers.toList()
+ else -> listOf(psiValue)
+ }
+
+ if (jComponentType == Class::class.java) {
+ val typeMirrors = arrayValues.map { (it as PsiClassObjectAccessExpression).operand.type.toJeType(manager) }
+ return MirroredTypesExceptionProxy(Collections.unmodifiableList(typeMirrors))
+ } else {
+ val arr = Array.newInstance(jComponentType, arrayValues.size)
+ arrayValues.forEachIndexed { i, componentPsiValue ->
+ val componentValue = getConstantValue(componentPsiValue, returnType.componentType, jComponentType, evaluator)
+ try { Array.set(arr, i, componentValue) } catch (e: IllegalArgumentException) { return null }
+ }
+ return arr
+ }
+ }
+ jReturnType.isEnum -> {
+ val enumConstant = (psiValue.originalElement as? PsiReference)?.resolve() as? PsiEnumConstant
+ ?: error("$psiValue can not be resolved to enum constant")
+ return AnnotationUtil.createEnumValue(jReturnType, enumConstant.name)
+ }
+ else -> return castPrimitiveValue(returnType, calculateConstantValue(psiValue, evaluator))
+ }
+}
+
+private fun castPrimitiveValue(type: PsiType, value: Any?): Any? = when (type) {
+ PsiType.BYTE -> byteValue(value)
+ PsiType.SHORT -> shortValue(value)
+ PsiType.INT -> intValue(value)
+ PsiType.CHAR -> charValue(value)
+ PsiType.BOOLEAN -> booleanValue(value)
+ PsiType.LONG -> longValue(value)
+ PsiType.FLOAT -> floatValue(value)
+ PsiType.DOUBLE -> doubleValue(value)
+ else -> unexpectedType(type)
+}
+
+private fun byteValue(value: Any?): Byte = (value as? Number)?.toByte() ?: 0
+private fun intValue(value: Any?): Int = (value as? Number)?.toInt() ?: 0
+private fun shortValue(value: Any?): Short = (value as? Number)?.toShort() ?: 0
+private fun booleanValue(value: Any?): Boolean = if (value == true) true else false
+private fun charValue(value: Any?): Char = value as? Char ?: 0.toChar()
+
+private fun longValue(value: Any?): Long = (value as? Number)?.toLong() ?: 0
+private fun floatValue(value: Any?): Float = (value as? Number)?.toFloat() ?: 0f
+private fun doubleValue(value: Any?): Double = (value as? Number)?.toDouble() ?: 0.0
+
+private fun calculateConstantValue(value: PsiAnnotationMemberValue?, evaluator: PsiConstantEvaluationHelper) = when (value) {
+ is PsiLiteral -> value.value
+ is KtLightAnnotation.LightExpressionValue<*> -> value.getConstantValue()
+ is PsiExpression -> evaluator.computeConstantExpression(value)
+ else -> null
+}
+
+private fun unexpectedType(type: String): Nothing = error("Unexpected type: $type")
+private fun unexpectedType(type: PsiType): Nothing = unexpectedType(type.presentableText)
+
+private class MirroredTypeExceptionProxy(@Transient private var type: TypeMirror?) : ExceptionProxy() {
+ private val typeString = type.toString()
+
+ @Suppress("IMPLICIT_CAST_TO_ANY")
+ override fun hashCode() = (if (type != null) type else typeString)?.hashCode() ?: 0
+ override fun equals(other: Any?) = type != null && other is MirroredTypeExceptionProxy && type == other.type
+ override fun toString() = typeString
+
+ override fun generateException() = MirroredTypeException(type)
+
+ // Explicitly set all transient fields.
+ private fun readObject(s: ObjectInputStream) {
+ s.defaultReadObject()
+ type = null
+ }
+
+ companion object {
+ private const val serialVersionUID: Long = 269
+ }
+}
+
+private class MirroredTypesExceptionProxy(@Transient private var types: List?) : ExceptionProxy() {
+ private val typeStrings: String = types.toString()
+
+ @Suppress("IMPLICIT_CAST_TO_ANY")
+ override fun hashCode() = (if (types != null) types else typeStrings)?.hashCode() ?: 0
+ override fun equals(other: Any?) = types != null && other is MirroredTypesExceptionProxy && types == other.types
+ override fun toString() = typeStrings
+
+ override fun generateException() = MirroredTypesException(types)
+
+ // Explicitly set all transient fields.
+ private fun readObject(s: ObjectInputStream) {
+ s.defaultReadObject()
+ types = null
+ }
+
+ companion object {
+ private const val serialVersionUID: Long = 269
+ }
+}
\ No newline at end of file
diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/annotationStubFactory.kt b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/annotationStubFactory.kt
deleted file mode 100644
index e712b450525..00000000000
--- a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/annotationStubFactory.kt
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright 2010-2016 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.java.model.internal
-
-import com.intellij.psi.*
-import org.jetbrains.kotlin.asJava.KtLightAnnotation
-import org.jetbrains.org.objectweb.asm.ClassWriter
-import org.jetbrains.org.objectweb.asm.Opcodes.*
-import org.jetbrains.org.objectweb.asm.Type
-import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
-import java.net.URL
-import java.net.URLClassLoader
-
-internal fun createAnnotation(
- annotation: PsiAnnotation,
- annotationDeclaration: PsiClass,
- annotationClass: Class<*>
-): Annotation? {
- val qualifiedName = annotationDeclaration.qualifiedName ?: return null
- val implQualifiedName = "stub." + qualifiedName + ".Impl" + Integer.toHexString(annotation.text.hashCode())
-
- val annotationInternalName = annotationDeclaration.getInternalName()
- val implInternalName = implQualifiedName.replace('.', '/')
-
- val bytes = createAnnotationImplementationClass(annotation, annotationDeclaration, annotationInternalName, implInternalName)
- return loadClass(implQualifiedName, bytes, annotationClass)?.newInstance() as? Annotation
-}
-
-private fun createAnnotationImplementationClass(
- annotation: PsiAnnotation,
- annotationDeclaration: PsiClass,
- annotationInternalName: String,
- implInternalName: String
-): ByteArray {
- return ClassWriter(ClassWriter.COMPUTE_FRAMES or ClassWriter.COMPUTE_MAXS).apply {
- visit(V1_6, ACC_SUPER or ACC_PUBLIC, implInternalName, null, "java/lang/Object", arrayOf(annotationInternalName))
-
- with(visitMethod(ACC_PUBLIC, "", "()V", null, null)) {
- visitCode()
- visitVarInsn(ALOAD, 0)
- visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false)
- visitInsn(RETURN)
- visitMaxs(-1, -1)
- visitEnd()
- }
-
- with(visitMethod(ACC_PUBLIC, "annotationType", "()Ljava/lang/Class;",
- "()Ljava/lang/Class<+Ljava/lang/annotation/Annotation;>;", null)) {
- visitCode()
- visitLdcInsn(Type.getType("L$annotationInternalName;"))
- visitInsn(ARETURN)
- visitMaxs(-1, -1)
- visitEnd()
- }
-
- if (annotationDeclaration.allMethods.isNotEmpty()) {
- val evaluator = JavaPsiFacade.getInstance(annotation.project).constantEvaluationHelper
-
- for (method in annotationDeclaration.methods) {
- if (method !is PsiAnnotationMethod) continue
-
- if (method.returnType == null) continue
- val returnType = method.returnType!!
-
- val value = annotation.findAttributeValue(method.name) ?: method.defaultValue
-
- when (returnType) {
- PsiType.VOID -> unexpectedType("void")
- PsiType.NULL -> unexpectedType("null")
- is PsiClassType -> {
- val resolvedClass = returnType.resolve()
- val resolvedQualifiedName = resolvedClass?.qualifiedName
- if (resolvedQualifiedName == "java.lang.String") {
- writeStringMethod(method, calculateConstantValue(value, evaluator))
- }
- else if (resolvedClass != null && resolvedClass.isEnum) {
- writeEnumMethod(method, resolvedClass, value)
- }
- else {
- unexpectedType("$resolvedQualifiedName")
- }
- }
- is PsiPrimitiveType -> writeLiteralMethod(method, calculateConstantValue(value, evaluator))
- is PsiArrayType -> writeArrayMethod(method, value, evaluator)
- else -> unexpectedType(returnType)
- }
- }
- }
-
- visitEnd()
- }.toByteArray()
-}
-
-private fun ClassWriter.writeEnumMethod(method: PsiAnnotationMethod, enumClass: PsiClass, value: PsiAnnotationMemberValue?) {
- val enumInternalName = enumClass.getInternalName()
- val enumConstant = (value?.originalElement as? PsiReference)?.resolve() as? PsiEnumConstant ?: return
-
- val mv = visitMethod(ACC_PUBLIC, method.name, "()L$enumInternalName;", null, null)
-
- with (InstructionAdapter(mv)) {
- visitCode()
-
- getstatic(enumInternalName, enumConstant.name!!, "L$enumInternalName;")
- visitInsn(ARETURN)
-
- visitMaxs(-1 ,-1)
- visitEnd()
- }
-}
-
-private fun ClassWriter.writeStringMethod(method: PsiAnnotationMethod, value: Any?) {
- val stringValue = (value as? String) ?: null
-
- val mv = visitMethod(ACC_PUBLIC, method.name, "()Ljava/lang/String;", null, null)
-
- with (InstructionAdapter(mv)) {
- visitCode()
-
- if (stringValue != null) {
- visitLdcInsn(stringValue)
- } else {
- visitInsn(ACONST_NULL)
- }
- visitInsn(ARETURN)
-
- visitMaxs(-1 ,-1)
- visitEnd()
- }
-}
-
-private fun ClassWriter.writeArrayMethod(
- method: PsiAnnotationMethod,
- value: PsiAnnotationMemberValue?,
- evaluator: PsiConstantEvaluationHelper
-) {
- val componentType = (method.returnType as? PsiArrayType)?.componentType ?: return
- val componentAsmType = componentType.toAsmType() ?: return
-
- val initializers = (value as? PsiArrayInitializerMemberValue)?.initializers ?: emptyArray()
-
- val mv = visitMethod(ACC_PUBLIC, method.name, "()[" + componentAsmType.descriptor, null, null)
-
- with (InstructionAdapter(mv)) {
- visitCode()
-
- iconst(initializers.size)
- newarray(componentAsmType)
-
- initializers.forEachIndexed { index, value ->
- val valueObject = calculateConstantValue(value, evaluator)
-
- dup()
- iconst(index)
- putValue(componentAsmType, valueObject)
- astore(componentAsmType)
- }
-
- visitInsn(ARETURN)
- visitMaxs(-1, -1)
- visitEnd()
- }
-}
-
-private fun calculateConstantValue(value: PsiAnnotationMemberValue?, evaluator: PsiConstantEvaluationHelper) = when (value) {
- is PsiLiteral -> value.value
- is KtLightAnnotation.LightExpressionValue<*> -> value.getConstantValue()
- is PsiExpression -> evaluator.computeConstantExpression(value)
- else -> null
-}
-
-private fun InstructionAdapter.putValue(type: Type, value: Any?) = when (type) {
- Type.DOUBLE_TYPE -> dconst(doubleValue(value))
- Type.FLOAT_TYPE -> fconst(floatValue(value))
- Type.LONG_TYPE -> lconst(longValue(value))
- Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE, Type.CHAR_TYPE, Type.BOOLEAN_TYPE -> iconst(type.castValue(value))
- else -> aconst(value)
-}
-
-private fun ClassWriter.writeLiteralMethod(method: PsiAnnotationMethod, value: Any?) {
- val returnType = method.returnType ?: return
- val asmType = returnType.toAsmType() ?: return
-
- val mv = visitMethod(ACC_PUBLIC, method.name, "()" + asmType.descriptor, null, null)
- with (InstructionAdapter(mv)) {
- visitCode()
-
- putValue(asmType, value)
- areturn(asmType)
-
- visitMaxs(-1, -1)
- visitEnd()
- }
-}
-
-private fun PsiType.toAsmType(): Type? = when (this) {
- PsiType.BYTE -> Type.BYTE_TYPE
- PsiType.SHORT -> Type.SHORT_TYPE
- PsiType.INT -> Type.INT_TYPE
- PsiType.CHAR -> Type.CHAR_TYPE
- PsiType.BOOLEAN -> Type.BOOLEAN_TYPE
- PsiType.LONG -> Type.LONG_TYPE
- PsiType.FLOAT -> Type.FLOAT_TYPE
- PsiType.DOUBLE -> Type.DOUBLE_TYPE
- is PsiClassType -> resolve()?.let { Type.getObjectType(it.getInternalName()) }
- else -> null
-}
-
-private fun Type.castValue(value: Any?): Int = when (this) {
- Type.BYTE_TYPE -> byteValue(value)
- Type.SHORT_TYPE -> shortValue(value)
- Type.INT_TYPE -> intValue(value)
- Type.CHAR_TYPE -> charValue(value)
- Type.BOOLEAN_TYPE -> booleanValue(value)
- else -> unexpectedType(this)
-}
-
-private fun PsiClass.getInternalName(): String {
- val containingClass = this.containingClass
- return if (containingClass != null) {
- containingClass.getInternalName() + "$" + this.name
- } else {
- qualifiedName?.replace('.', '/') ?: error("Invalid class name ($this)")
- }
-}
-
-private fun byteValue(value: Any?): Int = (value as? Number)?.toByte()?.toInt() ?: 0
-private fun intValue(value: Any?): Int = (value as? Number)?.toInt() ?: 0
-private fun shortValue(value: Any?): Int = (value as? Number)?.toShort()?.toInt() ?: 0
-private fun booleanValue(value: Any?): Int = if (value == true) 1 else 0
-private fun charValue(value: Any?): Int = (value as? Char)?.toInt() ?: 0.toChar().toInt()
-
-private fun longValue(value: Any?): Long = (value as? Number)?.toLong() ?: 0
-private fun floatValue(value: Any?): Float = (value as? Number)?.toFloat() ?: 0f
-private fun doubleValue(value: Any?): Double = (value as? Number)?.toDouble() ?: 0.0
-
-private fun loadClass(fqName: String, bytes: ByteArray, annotationClass: Class<*>): Class<*>? {
- class ByteClassLoader(
- urls: Array?,
- parent: ClassLoader?,
- val extraClasses: MutableMap,
- predefinedClasses: List>
- ) : URLClassLoader(urls, parent) {
- private val predefinedClasses = predefinedClasses.associateBy { it.canonicalName }
-
- override fun findClass(name: String): Class<*>? {
- return extraClasses.remove(name)?.let {
- defineClass(name, it, 0, it.size)
- } ?: predefinedClasses[name] ?: super.findClass(name)
- }
- }
-
- val classLoader = ByteClassLoader(emptyArray(), annotationClass.classLoader, hashMapOf(fqName to bytes), listOf())
- return Class.forName(fqName, false, classLoader)
-}
-
-private fun unexpectedType(type: String): Nothing = error("Unexpected type: $type")
-private fun unexpectedType(type: PsiType): Nothing = unexpectedType(type.presentableText)
-private fun unexpectedType(type: Type): Nothing = unexpectedType(type.descriptor)
\ No newline at end of file