diff --git a/plugins/kotlin/libs/metadata.jar b/plugins/kotlin/libs/metadata.jar
index e6cb285419..ddfe66f5b8 100644
Binary files a/plugins/kotlin/libs/metadata.jar and b/plugins/kotlin/libs/metadata.jar differ
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinChooser.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinChooser.java
index 308d26d885..e521e2a4b9 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinChooser.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinChooser.java
@@ -1,13 +1,11 @@
 package org.vineflower.kotlin;
 
-import kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf;
-import kotlin.reflect.jvm.internal.impl.metadata.jvm.JvmProtoBuf;
-import kotlin.reflect.jvm.internal.impl.protobuf.ExtensionRegistryLite;
+import kotlinx.metadata.internal.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.jvm.JvmProtoBuf;
+import kotlinx.metadata.internal.protobuf.ExtensionRegistryLite;
 import org.jetbrains.java.decompiler.api.plugin.LanguageChooser;
 import org.jetbrains.java.decompiler.main.DecompilerContext;
 import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
-import org.jetbrains.java.decompiler.util.Key;
-import org.vineflower.kotlin.metadata.BitEncoding;
 import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
 import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
 import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
@@ -15,6 +13,8 @@
 import org.jetbrains.java.decompiler.struct.StructClass;
 import org.jetbrains.java.decompiler.struct.attr.StructAnnotationAttribute;
 import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.util.Key;
+import org.vineflower.kotlin.metadata.BitEncoding;
 import org.vineflower.kotlin.metadata.MetadataNameResolver;
 
 import java.io.ByteArrayInputStream;
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinDecompilationContext.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinDecompilationContext.java
index 8594c8c31b..ebe8d99e06 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinDecompilationContext.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinDecompilationContext.java
@@ -1,6 +1,6 @@
 package org.vineflower.kotlin;
 
-import kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.ProtoBuf;
 import org.jetbrains.java.decompiler.main.DecompilerContext;
 import org.jetbrains.java.decompiler.util.Key;
 import org.vineflower.kotlin.metadata.MetadataNameResolver;
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinImportCollector.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinImportCollector.java
index 2cf27d887f..f8a20b6b43 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinImportCollector.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinImportCollector.java
@@ -1,12 +1,21 @@
 package org.vineflower.kotlin;
 
+import org.jetbrains.java.decompiler.main.ClassesProcessor;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
 import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.struct.StructContext;
 import org.jetbrains.java.decompiler.util.TextBuffer;
+import org.vineflower.kotlin.util.KTypes;
 
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-public class KotlinImportCollector {
-  private static final String[] AUTO_KOTLIN_IMPORTS = {
+public class KotlinImportCollector extends ImportCollector {
+  public static final String[] AUTO_KOTLIN_IMPORTS = {
     "annotation",
     "collections",
     "comparisons",
@@ -17,45 +26,48 @@ public class KotlinImportCollector {
     "text",
   };
 
-  private final ImportCollector parent;
-
   public KotlinImportCollector(ImportCollector parent) {
-    this.parent = parent;
-  }
+    super(parent);
 
-  public void writeImports(TextBuffer buffer, boolean addSeparator) {
-    TextBuffer buf = new TextBuffer();
-    parent.writeImports(buf, false);
-    String[] imports = buf.convertToStringAndAllowDataDiscard().split("\n");
-    boolean imported = false;
-    for (String line : imports) {
-      if (line.isBlank()) {
-        continue;
-      }
-      line = line.trim();
-      String importLine = line.substring(7, line.length() - 1);
-      String[] parts = importLine.split("\\.");
-
-      // Don't include automatic kotlin imports
-      if (parts.length == 2 && parts[0].equals("kotlin")) {
-        continue;
-      } else if (parts.length == 3 && parts[0].equals("kotlin") && Arrays.binarySearch(AUTO_KOTLIN_IMPORTS, parts[1]) >= 0) {
-        continue;
+    // Any class that Kotlin "overrides" requires explicit non-imported references
+    for (String className : KTypes.KOTLIN_TO_JAVA_LANG.keySet()) {
+      String simpleName = className.substring(className.lastIndexOf('/') + 1);
+      String packageName = className.substring(0, className.lastIndexOf('/')).replace('/', '.');
+      if (!mapSimpleNames.containsKey(simpleName)) {
+        mapSimpleNames.put(simpleName, packageName);
       }
+    }
 
-      buffer.append("import ");
-      boolean first = true;
-      for (String part : parts) {
-        if (!first) {
-          buffer.append(".");
-        }
-        first = false;
-        buffer.append(KotlinWriter.toValidKotlinIdentifier(part));
+    for (String className : KTypes.KOTLIN_TO_JAVA_UTIL.keySet()) {
+      String simpleName = className.substring(className.lastIndexOf('/') + 1);
+      String packageName = className.substring(0, className.lastIndexOf('/')).replace('/', '.');
+      if (!mapSimpleNames.containsKey(simpleName)) {
+        mapSimpleNames.put(simpleName, packageName);
       }
-      buffer.appendLineSeparator();
-      imported = true;
     }
-    if (imported && addSeparator) {
+  }
+
+  @Override
+  protected boolean keepImport(Map.Entry<String, String> ent) {
+    if (!super.keepImport(ent)) return false;
+    if (ent.getValue().equals("kotlin")) return false;
+    for (String autoImport : AUTO_KOTLIN_IMPORTS) {
+      if (ent.getValue().equals("kotlin." + autoImport)) return false;
+    }
+    return true;
+  }
+
+  @Override
+  public void writeImports(TextBuffer buffer, boolean addSeparator) {
+    if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_IMPORTS)) {
+      return;
+    }
+
+    List<String> imports = packImports();
+    for (String imp : imports) {
+      buffer.append("import ").append(imp).appendLineSeparator();
+    }
+    if (addSeparator && !imports.isEmpty()) {
       buffer.appendLineSeparator();
     }
   }
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinWriter.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinWriter.java
index c7358022d6..61dad6f0fc 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinWriter.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinWriter.java
@@ -1,7 +1,7 @@
 // Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package org.vineflower.kotlin;
 
-import kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.ProtoBuf;
 import net.fabricmc.fernflower.api.IFabricJavadocProvider;
 import org.jetbrains.java.decompiler.api.plugin.StatementWriter;
 import org.jetbrains.java.decompiler.code.CodeConstants;
@@ -32,15 +32,13 @@
 import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor;
 import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor;
 import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor;
-import org.jetbrains.java.decompiler.util.InterpreterUtil;
-import org.jetbrains.java.decompiler.util.Key;
-import org.jetbrains.java.decompiler.util.TextBuffer;
-import org.jetbrains.java.decompiler.util.TextUtil;
+import org.jetbrains.java.decompiler.util.*;
 import org.jetbrains.java.decompiler.util.collections.VBStyleCollection;
 import org.vineflower.kotlin.expr.KAnnotationExprent;
 import org.vineflower.kotlin.metadata.MetadataNameResolver;
-import org.vineflower.kotlin.struct.KProperty;
+import org.vineflower.kotlin.struct.*;
 import org.vineflower.kotlin.util.KTypes;
+import org.vineflower.kotlin.util.KUtils;
 import org.vineflower.kotlin.util.ProtobufFlags;
 
 import java.io.IOException;
@@ -55,6 +53,7 @@ public class KotlinWriter implements StatementWriter {
   ));
   private static final String NOT_NULL_ANN_NAME = "org/jetbrains/annotations/NotNull";
   private static final String NULLABLE_ANN_NAME = "org/jetbrains/annotations/Nullable";
+  private static final String REPEATABLE_ANN_NAME = "java/lang/annotation/Repeatable";
   private static final Set<String> KT_HARD_KEYWORDS = new HashSet<>(Arrays.asList(
     "as",
     "break",
@@ -85,7 +84,7 @@ public class KotlinWriter implements StatementWriter {
     "when",
     "while"
   ));
-  
+
   private final PoolInterceptor interceptor;
   private final IFabricJavadocProvider javadocProvider;
 
@@ -202,6 +201,7 @@ public void writeClassHeader(StructClass cl, TextBuffer buffer, ImportCollector
   public void writeClass(ClassNode node, TextBuffer buffer, int indent) {
     ClassNode outerNode = DecompilerContext.getContextProperty(DecompilerContext.CURRENT_CLASS_NODE);
     DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);
+    DecompilerContext.setImportCollector(new KotlinImportCollector(DecompilerContext.getImportCollector()));
 
     try {
       // last minute processing
@@ -213,15 +213,21 @@ public void writeClass(ClassNode node, TextBuffer buffer, int indent) {
 
       ClassWrapper wrapper = node.getWrapper();
       StructClass cl = wrapper.getClassStruct();
+      ConstantPool pool = cl.getPool();
+
+      KotlinChooser.setContextVariables(cl);
 
       DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);
 
+      KProperty.Data propertyData = KProperty.parse(node);
+      Map<StructMethod, KFunction> functions = KFunction.parse(node);
+      KConstructor.Data constructorData = KConstructor.parse(node);
+
       if (DecompilerContext.getOption(IFernflowerPreferences.SOURCE_FILE_COMMENTS)) {
         StructSourceFileAttribute sourceFileAttr = node.classStruct
           .getAttribute(StructGeneralAttribute.ATTRIBUTE_SOURCE_FILE);
 
         if (sourceFileAttr != null) {
-          ConstantPool pool = node.classStruct.getPool();
           String sourceFile = sourceFileAttr.getSourceFile(pool);
 
           buffer
@@ -233,19 +239,17 @@ public void writeClass(ClassNode node, TextBuffer buffer, int indent) {
 
       if (cl.hasModifier(CodeConstants.ACC_ANNOTATION)) {
         // Kotlin's annotation classes are treated quite differently from other classes
-        writeAnnotationDefinition(node, buffer, indent);
+        writeAnnotationDefinition(node, buffer, indent, propertyData, functions, constructorData);
         return;
       }
 
       if (KotlinDecompilationContext.getCurrentType() == KotlinDecompilationContext.KotlinType.FILE) {
-        writeKotlinFile(node, buffer, indent);
+        writeKotlinFile(node, buffer, indent, propertyData, functions); // no constructors in top level file
         return;
       }
 
       // write class definition
-      writeClassDefinition(node, buffer, indent);
-
-      KProperty.Data propertyData = KProperty.parse(node);
+      writeClassDefinition(node, buffer, indent, constructorData);
 
       boolean hasContent = false;
       boolean enumFields = false;
@@ -294,8 +298,7 @@ public void writeClass(ClassNode node, TextBuffer buffer, int indent) {
             buffer.append(',').appendLineSeparator();
           }
           enumFields = true;
-        }
-        else if (enumFields) {
+        } else if (enumFields) {
           buffer.append(';');
           buffer.appendLineSeparator();
           buffer.appendLineSeparator();
@@ -351,9 +354,31 @@ else if (enumFields) {
         boolean hide = mt.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
           mt.hasModifier(CodeConstants.ACC_BRIDGE) && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE) ||
           wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor())) ||
-          (propertyData != null && propertyData.associatedMethods.contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor())));
+          mt.getName().equals("<init>") && mt.getDescriptor().equals("(Lkotlin/jvm/internal/DefaultConstructorMarker;)V") ||
+          propertyData != null && propertyData.associatedMethods.contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
         if (hide) continue;
 
+        KFunction function = functions.get(mt);
+        if (function != null) {
+          if (hasContent) {
+            buffer.appendLineSeparator();
+          }
+          hasContent = true;
+          buffer.append(function.stringify(indent + 1));
+          continue;
+        }
+
+        if (constructorData != null) {
+          KConstructor constructor = constructorData.constructors.get(mt);
+          if (constructor != null) {
+            if (hasContent) {
+              buffer.appendLineSeparator();
+            }
+            hasContent |= constructor.stringify(buffer, indent + 1);
+            continue;
+          }
+        }
+
         TextBuffer methodBuffer = new TextBuffer();
         boolean methodSkipped = !writeMethod(node, mt, i, methodBuffer, indent + 1);
         if (!methodSkipped) {
@@ -388,17 +413,15 @@ else if (enumFields) {
       if (node.type != ClassNode.Type.ANONYMOUS) {
         buffer.appendLineSeparator();
       }
-    }
-    finally {
+    } finally {
       DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode);
       DecompilerContext.getLogger().endWriteClass();
     }
   }
 
-  private void writeKotlinFile(ClassNode node, TextBuffer buffer, int indent) {
+  private void writeKotlinFile(ClassNode node, TextBuffer buffer, int indent, KProperty.Data propertyData, Map<StructMethod, KFunction> functions) {
     ClassWrapper wrapper = node.getWrapper();
     StructClass cl = wrapper.getClassStruct();
-    KProperty.Data propertyData = KProperty.parse(node);
 
     for (KProperty property : propertyData.properties) {
       buffer.append(property.stringify(indent));
@@ -419,6 +442,12 @@ private void writeKotlinFile(ClassNode node, TextBuffer buffer, int indent) {
 
     for (int i = 0; i < cl.getMethods().size(); i++) {
       StructMethod mt = cl.getMethods().get(i);
+      if (functions.containsKey(mt)) {
+        buffer.append(functions.get(mt).stringify(indent));
+        buffer.appendLineSeparator();
+        continue;
+      }
+
       String key = InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor());
       if (mt.getName().equals("<clinit>") || propertyData.associatedMethods.contains(key)) continue;
 
@@ -436,10 +465,23 @@ private void writeKotlinFile(ClassNode node, TextBuffer buffer, int indent) {
     }
   }
 
-  private void writeAnnotationDefinition(ClassesProcessor.ClassNode node, TextBuffer buffer, int indent) {
+  private void writeAnnotationDefinition(ClassNode node, TextBuffer buffer, int indent, KProperty.Data propertyData, Map<StructMethod, KFunction> functions, KConstructor.Data constructorData) {
     ClassWrapper wrapper = node.getWrapper();
     StructClass cl = wrapper.getClassStruct();
 
+    StructAnnotationAttribute runtimeAnnotations = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS);
+    AnnotationExprent repeatableAnnotation = runtimeAnnotations.getAnnotations().stream()
+      .filter(a -> REPEATABLE_ANN_NAME.equals(a.getClassName()))
+      .findFirst()
+      .orElse(null);
+
+    String repeatableContainer = null;
+
+    if (repeatableAnnotation != null) {
+      repeatableContainer = ((ConstExprent) repeatableAnnotation.getParValues().get(0)).getValue().toString();
+      runtimeAnnotations.getAnnotations().remove(repeatableAnnotation);
+    }
+
     appendAnnotations(buffer, indent, cl, -1);
     appendJvmAnnotations(buffer, indent, cl, true, cl.getPool(), TypeAnnotation.CLASS_TYPE_PARAMETER);
 
@@ -453,89 +495,88 @@ private void writeAnnotationDefinition(ClassesProcessor.ClassNode node, TextBuff
       .append("(")
       .appendLineSeparator();
 
-    boolean hasCompanion = !cl.getFields().isEmpty();
-
-    if (!cl.getMethods().isEmpty()) {
-      boolean first = true;
-      for (StructMethod mt : cl.getMethods()) {
-        if (mt.hasModifier(CodeConstants.ACC_STATIC)) {
-          hasCompanion = true;
-          continue;
-        }
+    List<KProperty> nonParameterProperties = new ArrayList<>(propertyData.properties);
 
-        if (first) {
-          first = false;
-        } else {
-          buffer.append(',').appendLineSeparator();
-        }
-
-        buffer.appendIndent(indent + 1)
-          .append("val ")
-          .append(mt.getName())
-          .append(": ");
-
-        String type = mt.getDescriptor().substring(2);
-        VarType varType = new VarType(type, false);
-
-        buffer.append(KTypes.getKotlinType(varType));
-
-        if (mt.hasAttribute(StructGeneralAttribute.ATTRIBUTE_ANNOTATION_DEFAULT)) {
-          buffer.append(" = ");
-          StructAnnDefaultAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_ANNOTATION_DEFAULT);
-          KAnnotationExprent.writeAnnotationValue(attr.getDefaultValue(), buffer);
+    boolean first = true;
+    for (KParameter param : constructorData.primary.parameters) {
+      if (!first) {
+        buffer.append(",").appendLineSeparator();
+      }
+      first = false;
+      buffer.appendIndent(indent + 1)
+        .append("val ")
+        .append(KotlinWriter.toValidKotlinIdentifier(param.name))
+        .append(": ")
+        .append(param.type.stringify(indent + 1));
+
+      // Because Kotlin really doesn't like making this easy for us, defaults are still passed directly via attributes
+      KProperty prop = propertyData.properties.stream()
+        .filter(p -> p.name.equals(param.name))
+        .findFirst()
+        .orElseThrow();
+
+      nonParameterProperties.remove(prop);
+
+      KPropertyAccessor getter = prop.getter;
+      if (getter != null) {
+        StructMethod mt = getter.underlyingMethod.methodStruct;
+        StructAnnDefaultAttribute paramAttr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_ANNOTATION_DEFAULT);
+        if (paramAttr != null) {
+          Exprent kExpr = KUtils.replaceExprent(paramAttr.getDefaultValue());
+          Exprent expr = kExpr != null ? kExpr : paramAttr.getDefaultValue();
+          buffer.append(" = ").append(expr.toJava());
         }
       }
-
-      buffer.appendLineSeparator().appendIndent(indent).append(')');
     }
 
-    if (hasCompanion || !node.nested.isEmpty()) {
-      buffer.append(" {").appendLineSeparator();
+    buffer.appendLineSeparator()
+      .appendIndent(indent)
+      .append(")");
 
-      // member classes
-      boolean first = false;
-      for (ClassNode inner : node.nested) {
-        if (inner.type == ClassNode.Type.MEMBER) {
-          StructClass innerCl = inner.classStruct;
-          boolean isSynthetic = (inner.access & CodeConstants.ACC_SYNTHETIC) != 0 || innerCl.isSynthetic();
-          boolean hide = isSynthetic && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
-            wrapper.getHiddenMembers().contains(innerCl.qualifiedName);
-          if (hide) continue;
+    boolean appended = false;
 
-          if (first) {
-            buffer.appendLineSeparator();
-          }
-          writeClass(inner, buffer, indent + 1);
+    TextBuffer innerBuffer = new TextBuffer();
 
-          first = true;
-        }
-      }
+    for (KProperty prop : nonParameterProperties) {
+      innerBuffer.append(prop.stringify(indent + 1));
+      appended = true;
+    }
 
-      if (hasCompanion) {
-        buffer.appendIndent(indent + 1).append("companion object {").appendLineSeparator();
+    first = true;
+    for (KFunction function : functions.values()) {
+      if (!first || appended) {
+        innerBuffer.appendLineSeparator();
+      }
+      first = false;
 
-        for (StructField fd : cl.getFields()) {
-          if (!fd.hasModifier(CodeConstants.ACC_STATIC)) {
-            appendComment(buffer, "Illegal field (must be static): " + fd.getName(), indent + 2);
-          }
+      innerBuffer.append(function.stringify(indent + 1));
+      appended = true;
+    }
 
-          writeField(wrapper, cl, fd, buffer, indent + 2);
-          buffer.appendLineSeparator();
+    first = true;
+    for (ClassNode inner : node.nested) {
+      if (inner.type == ClassNode.Type.MEMBER) {
+        if (inner.classStruct.qualifiedName.equals(repeatableContainer)) {
+          // Skip the container class
+          continue;
         }
 
-        for (StructMethod mt : cl.getMethods()) {
-          if (!mt.hasModifier(CodeConstants.ACC_STATIC)) {
-            continue;
-          }
-
-          writeMethod(node, mt, 0, buffer, indent + 2);
-          buffer.appendLineSeparator();
+        if (!first || appended) {
+          innerBuffer.appendLineSeparator();
         }
+        first = false;
 
-        buffer.appendIndent(indent + 1).append('}').appendLineSeparator();
+        writeClass(inner, innerBuffer, indent + 1);
+        appended = true;
       }
+    }
 
-      buffer.appendIndent(indent).append('}');
+    if (appended) {
+      buffer.append(" {")
+        .appendLineSeparator()
+        .append(innerBuffer)
+        .appendIndent(indent)
+        .append("}");
     }
 
     buffer.appendLineSeparator();
@@ -545,7 +586,7 @@ private static boolean isGenerated(int flags) {
     return (flags & (CodeConstants.ACC_SYNTHETIC | CodeConstants.ACC_MANDATED)) != 0;
   }
 
-  private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) {
+  private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent, KConstructor.Data constructorData) {
     if (node.type == ClassNode.Type.ANONYMOUS) {
       buffer.append(" {").appendLineSeparator();
       return;
@@ -554,9 +595,6 @@ private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent)
     ClassWrapper wrapper = node.getWrapper();
     StructClass cl = wrapper.getClassStruct();
 
-    // Ensure that the class data is put in place
-    KotlinChooser.setContextVariables(cl);
-
     int flags = node.type == ClassNode.Type.ROOT ? cl.getAccessFlags() : node.access;
     boolean isDeprecated = cl.hasAttribute(StructGeneralAttribute.ATTRIBUTE_DEPRECATED);
     boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || cl.hasAttribute(StructGeneralAttribute.ATTRIBUTE_SYNTHETIC);
@@ -653,12 +691,16 @@ private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent)
 
     boolean appendedColon = false;
     if (!isEnum && !isInterface && cl.superClass != null) {
-      VarType supertype = new VarType(cl.superClass.getString(), true);
-      if (!VarType.VARTYPE_OBJECT.equals(supertype)) {
-        buffer.append(" :");
-        buffer.appendPossibleNewline(" ");
-        buffer.append(ExprProcessor.getCastTypeName(descriptor == null ? supertype : descriptor.superclass));
+      if (constructorData != null && constructorData.primary != null && constructorData.primary.writePrimaryConstructor(buffer, indent)) {
         appendedColon = true;
+      } else {
+        VarType supertype = new VarType(cl.superClass.getString(), true);
+        if (!VarType.VARTYPE_OBJECT.equals(supertype)) {
+          buffer.appendPossibleNewline(" ");
+          buffer.append(": ");
+          buffer.append(ExprProcessor.getCastTypeName(descriptor == null ? supertype : descriptor.superclass));
+          appendedColon = true;
+        }
       }
     }
 
@@ -757,18 +799,16 @@ public void writeField(ClassWrapper wrapper, StructClass cl, StructField fd, Tex
     Exprent initializer;
     if (fd.hasModifier(CodeConstants.ACC_STATIC)) {
       initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
-    }
-    else {
+    } else {
       initializer = wrapper.getDynamicFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
     }
 
     if (initializer != null) {
       if (isEnum && initializer instanceof NewExprent) {
-        NewExprent expr = (NewExprent)initializer;
+        NewExprent expr = (NewExprent) initializer;
         expr.setEnumConst(true);
         buffer.append(expr.toJava(indent));
-      }
-      else {
+      } else {
         buffer.append(" = ");
 
         if (initializer instanceof ConstExprent) {
@@ -778,8 +818,7 @@ public void writeField(ClassWrapper wrapper, StructClass cl, StructField fd, Tex
         // FIXME: special case field initializer. Can map to more than one method (constructor) and bytecode instruction.
         ExprProcessor.getCastedExprent(initializer, descriptor == null ? fieldType : descriptor.type, buffer, indent, false);
       }
-    }
-    else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) {
+    } else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) {
       StructConstantValueAttribute attr = fd.getAttribute(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE);
       if (attr != null) {
         PrimitiveConstant constant = cl.getPool().getPrimitiveConstant(attr.getIndex());
@@ -827,7 +866,7 @@ public boolean writeMethod(ClassNode node, StructMethod mt, int methodIndex, Tex
 
     boolean hideMethod = false;
 
-    MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getContextProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+    MethodWrapper outerWrapper = (MethodWrapper) DecompilerContext.getContextProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
     DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);
 
     try {
@@ -908,7 +947,7 @@ public boolean writeMethod(ClassNode node, StructMethod mt, int methodIndex, Tex
       }
 
       boolean didOverride = false;
-      if (!CodeConstants.INIT_NAME.equals(mt.getName()) && !CodeConstants.CLINIT_NAME.equals(mt.getName()) && !mt.hasModifier(CodeConstants.ACC_STATIC)  && !mt.hasModifier(CodeConstants.ACC_PRIVATE)) {
+      if (!CodeConstants.INIT_NAME.equals(mt.getName()) && !CodeConstants.CLINIT_NAME.equals(mt.getName()) && !mt.hasModifier(CodeConstants.ACC_STATIC) && !mt.hasModifier(CodeConstants.ACC_PRIVATE)) {
         // Search superclasses for methods that match the name and descriptor of this one.
         // Make sure not to search the current class otherwise it will return the current method itself!
         // TODO: record overrides
@@ -1014,38 +1053,36 @@ public boolean writeMethod(ClassNode node, StructMethod mt, int methodIndex, Tex
               buffer.appendPossibleNewline(" ");
             }
             first = false;
-            
+
             // @PAnn vararg? pName: pTy
             boolean nullable = processParameterAnnotations(buffer, mt, paramCount);
-  
+
             boolean isVarArg = i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arrayDim > 0;
             if (isVarArg) {
               buffer.append("vararg ");
             }
-            
+
             String parameterName;
             if (methodParameters != null && i < methodParameters.size()) {
               parameterName = methodParameters.get(i).myName;
-            }
-            else {
+            } else {
               parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0));
             }
-  
+
             if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) {
               String newParameterName = methodWrapper.methodStruct.getVariableNamer().renameAbstractParameter(parameterName, index);
               parameterName = !newParameterName.equals(parameterName) ? newParameterName : DecompilerContext.getStructContext().renameAbstractParameter(methodWrapper.methodStruct.getClassQualifiedName(), mt.getName(), mt.getDescriptor(), index - (((flags & CodeConstants.ACC_STATIC) == 0) ? 1 : 0), parameterName);
-    
+
             }
 
             parameterName = toValidKotlinIdentifier(parameterName);
-  
+
             buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
             buffer.append(": ");
 
             if (methodParameters != null && i < methodParameters.size()) {
               appendModifiers(buffer, methodParameters.get(i).myAccessFlags, CodeConstants.ACC_FINAL, isInterface, 0);
-            }
-            else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarTypeProcessor.FinalType.EXPLICIT_FINAL) {
+            } else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarTypeProcessor.FinalType.EXPLICIT_FINAL) {
               buffer.append("final ");
             }
 
@@ -1094,8 +1131,7 @@ else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarT
 
       if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) { // native or abstract method (explicit or interface)
         buffer.appendLineSeparator();
-      }
-      else {
+      } else {
         if (!clInit && !dInit) {
           buffer.append(' ');
         }
@@ -1104,8 +1140,7 @@ else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarT
 
         hideMethod = !writeMethodBody(node, methodWrapper, buffer, indent, hideIfInit);
       }
-    }
-    finally {
+    } finally {
       DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
     }
 
@@ -1136,8 +1171,7 @@ public static boolean writeMethodBody(ClassNode node, MethodWrapper methodWrappe
           hideMethod = code.length() == 0 && hideIfInit;
           buffer.append(code, cl.qualifiedName, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
         }
-      }
-      catch (Throwable t) {
+      } catch (Throwable t) {
         String message = "Method " + mt.getName() + " " + mt.getDescriptor() + " in class " + node.classStruct.qualifiedName + " couldn't be written.";
         DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN, t);
         methodWrapper.decompileError = t;
@@ -1151,7 +1185,7 @@ public static boolean writeMethodBody(ClassNode node, MethodWrapper methodWrappe
     return !hideMethod;
   }
 
-  private static void dumpError(TextBuffer buffer, MethodWrapper wrapper, int indent) {
+  public static void dumpError(TextBuffer buffer, MethodWrapper wrapper, int indent) {
     List<String> lines = new ArrayList<>();
     lines.add("$VF: Couldn't be decompiled");
     boolean exceptions = DecompilerContext.getOption(IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR);
@@ -1219,7 +1253,7 @@ public static void collectErrorLines(Throwable error, List<String> lines) {
   }
 
   private static void collectBytecode(MethodWrapper wrapper, List<String> lines) throws IOException {
-    ClassNode classNode = (ClassNode)DecompilerContext.getContextProperty(DecompilerContext.CURRENT_CLASS_NODE);
+    ClassNode classNode = (ClassNode) DecompilerContext.getContextProperty(DecompilerContext.CURRENT_CLASS_NODE);
     StructMethod method = wrapper.methodStruct;
     InstructionSequence instructions = method.getInstructionSequence();
     if (instructions == null) {
@@ -1337,7 +1371,7 @@ private static void appendConstant(StringBuilder sb, PooledConstant constant) {
     }
   }
 
-  private static boolean hideConstructor(ClassNode node, boolean init, boolean throwsExceptions, int paramCount, int methodAccessFlags) {
+  public static boolean hideConstructor(ClassNode node, boolean init, boolean throwsExceptions, int paramCount, int methodAccessFlags) {
     if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
       return false;
     }
@@ -1349,7 +1383,7 @@ private static boolean hideConstructor(ClassNode node, boolean init, boolean thr
     boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
 
     // default constructor requires same accessibility flags. Exception: enum constructor which is always private
-    if(!isEnum && ((classAccessFlags & ACCESSIBILITY_FLAGS) != (methodAccessFlags & ACCESSIBILITY_FLAGS))) {
+    if (!isEnum && ((classAccessFlags & ACCESSIBILITY_FLAGS) != (methodAccessFlags & ACCESSIBILITY_FLAGS))) {
       return false;
     }
 
@@ -1469,7 +1503,7 @@ private static void appendJavadoc(TextBuffer buffer, String javaDoc, int indent)
   static final Key<?>[] TYPE_ANNOTATION_ATTRIBUTES = {
     StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS};
 
-  static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, int targetType) {
+  public static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, int targetType) {
     Set<String> filter = new HashSet<>();
 
     for (Key<?> key : ANNOTATION_ATTRIBUTES) {
@@ -1490,8 +1524,7 @@ static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, in
           buffer.append(text);
           if (indent < 0) {
             buffer.append(' ');
-          }
-          else {
+          } else {
             buffer.appendLineSeparator();
           }
         }
@@ -1501,7 +1534,7 @@ static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, in
     appendTypeAnnotations(buffer, indent, mb, targetType, -1, filter);
   }
 
-  private static void appendJvmAnnotations(TextBuffer buffer, int indent, StructMember mb, boolean isInterface, ConstantPool pool, int targetType) {
+  public static void appendJvmAnnotations(TextBuffer buffer, int indent, StructMember mb, boolean isInterface, ConstantPool pool, int targetType) {
     switch (targetType) {
       case TypeAnnotation.METHOD_RETURN_TYPE:
         if (isInterface && !mb.hasModifier(CodeConstants.ACC_ABSTRACT)) {
@@ -1552,10 +1585,10 @@ private static void appendJvmAnnotations(TextBuffer buffer, int indent, StructMe
       buffer.appendIndent(indent).append("@JvmSynthetic").appendLineSeparator();
     }
   }
-  
-  static boolean isNullable(StructMember mb){
-    for (Key<?> key : ANNOTATION_ATTRIBUTES){
-      StructAnnotationAttribute attribute = (StructAnnotationAttribute)mb.getAttribute(key);
+
+  static boolean isNullable(StructMember mb) {
+    for (Key<?> key : ANNOTATION_ATTRIBUTES) {
+      StructAnnotationAttribute attribute = (StructAnnotationAttribute) mb.getAttribute(key);
       if (attribute != null) {
         return attribute.getAnnotations().stream().anyMatch(annotation -> annotation.getClassName().equals(NULLABLE_ANN_NAME));
       }
@@ -1564,7 +1597,7 @@ static boolean isNullable(StructMember mb){
   }
 
   // Returns true if a method with the given name and descriptor matches in the inheritance tree of the superclass.
-  private static boolean searchForMethod(StructClass cl, String name, MethodDescriptor md, boolean search) {
+  public static boolean searchForMethod(StructClass cl, String name, MethodDescriptor md, boolean search) {
     // Didn't find the class or the library containing the class wasn't loaded, can't search
     if (cl == null) {
       return false;
@@ -1585,7 +1618,7 @@ private static boolean searchForMethod(StructClass cl, String name, MethodDescri
 
     // If we have a superclass that's not Object, search that as well
     if (cl.superClass != null) {
-      StructClass superClass = DecompilerContext.getStructContext().getClass((String)cl.superClass.value);
+      StructClass superClass = DecompilerContext.getStructContext().getClass((String) cl.superClass.value);
 
       boolean foundInSuperClass = searchForMethod(superClass, name, md, true);
 
@@ -1609,12 +1642,12 @@ private static boolean searchForMethod(StructClass cl, String name, MethodDescri
     return false;
   }
 
-  private static boolean processParameterAnnotations(TextBuffer buffer, StructMethod mt, int param) {
+  public static boolean processParameterAnnotations(TextBuffer buffer, StructMethod mt, int param) {
     Set<String> filter = new HashSet<>();
     boolean ret = false;
 
     for (Key<?> key : PARAMETER_ANNOTATION_ATTRIBUTES) {
-      StructAnnotationParameterAttribute attribute = (StructAnnotationParameterAttribute)mt.getAttribute(key);
+      StructAnnotationParameterAttribute attribute = (StructAnnotationParameterAttribute) mt.getAttribute(key);
       if (attribute != null) {
         List<List<AnnotationExprent>> annotations = attribute.getParamAnnotations();
         if (param < annotations.size()) {
@@ -1639,7 +1672,7 @@ private static boolean processParameterAnnotations(TextBuffer buffer, StructMeth
 
   private static void appendTypeAnnotations(TextBuffer buffer, int indent, StructMember mb, int targetType, int index, Set<String> filter) {
     for (Key<?> key : TYPE_ANNOTATION_ATTRIBUTES) {
-      StructTypeAnnotationAttribute attribute = (StructTypeAnnotationAttribute)mb.getAttribute(key);
+      StructTypeAnnotationAttribute attribute = (StructTypeAnnotationAttribute) mb.getAttribute(key);
       if (attribute != null) {
         for (TypeAnnotation annotation : attribute.getAnnotations()) {
           if (annotation.isTopLevel() && annotation.getTargetType() == targetType && (index < 0 || annotation.getIndex() == index)) {
@@ -1648,8 +1681,7 @@ private static void appendTypeAnnotations(TextBuffer buffer, int indent, StructM
               buffer.append(text);
               if (indent < 0) {
                 buffer.append(' ');
-              }
-              else {
+              } else {
                 buffer.appendLineSeparator();
               }
             }
@@ -1660,6 +1692,7 @@ private static void appendTypeAnnotations(TextBuffer buffer, int indent, StructM
   }
 
   private static final Map<Integer, String> MODIFIERS;
+
   static {
     MODIFIERS = new LinkedHashMap<>();
     MODIFIERS.put(CodeConstants.ACC_PUBLIC, "public");
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KFunctionExprent.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KFunctionExprent.java
index 0f6a9a45dc..0aa6baad6a 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KFunctionExprent.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KFunctionExprent.java
@@ -1,6 +1,7 @@
 package org.vineflower.kotlin.expr;
 
 import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.plugins.PluginImplementationException;
 import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
 import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
 import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
@@ -42,7 +43,13 @@ public KFunctionExprent(FunctionType funcType, List<Exprent> operands, BitSet by
   public KFunctionExprent(FunctionExprent func) {
     super(func.getFuncType(), new ArrayList<>(KUtils.replaceExprents(func.getLstOperands())), func.bytecode);
 
-    setImplicitType(func.getExprType());
+    if (func instanceof KFunctionExprent) {
+      KFunctionExprent kFunc = (KFunctionExprent) func;
+      this.kType = kFunc.kType;
+    } else {
+      setImplicitType(func.getExprType());
+    }
+
     setNeedsCast(func.doesCast());
 
     if (getFuncType() == FunctionType.EQ) {
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/metadata/MetadataNameResolver.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/metadata/MetadataNameResolver.java
index 4bc0cbcfa8..9108149bc5 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/metadata/MetadataNameResolver.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/metadata/MetadataNameResolver.java
@@ -1,6 +1,6 @@
 package org.vineflower.kotlin.metadata;
 
-import kotlin.reflect.jvm.internal.impl.metadata.jvm.JvmProtoBuf;
+import kotlinx.metadata.internal.metadata.jvm.JvmProtoBuf;
 
 import java.util.*;
 
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KConstructor.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KConstructor.java
new file mode 100644
index 0000000000..c3af6c4163
--- /dev/null
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KConstructor.java
@@ -0,0 +1,280 @@
+package org.vineflower.kotlin.struct;
+
+import kotlinx.metadata.internal.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.jvm.JvmProtoBuf;
+import org.jetbrains.java.decompiler.main.ClassesProcessor;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.TypeAnnotation;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.TextBuffer;
+import org.vineflower.kotlin.KotlinDecompilationContext;
+import org.vineflower.kotlin.KotlinOptions;
+import org.vineflower.kotlin.KotlinWriter;
+import org.vineflower.kotlin.metadata.MetadataNameResolver;
+import org.vineflower.kotlin.util.KUtils;
+import org.vineflower.kotlin.util.ProtobufFlags;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class KConstructor {
+  private static final VarType DEFAULT_CONSTRUCTOR_MARKER = new VarType("kotlin/jvm/internal/DefaultConstructorMarker", true);
+
+  public final ProtobufFlags.Constructor flags;
+  public final KParameter[] parameters;
+  public final boolean isPrimary;
+
+  public final MethodWrapper method;
+  private final ClassesProcessor.ClassNode node;
+
+  private KConstructor(
+    KParameter[] parameters,
+    ProtobufFlags.Constructor flags,
+    MethodWrapper method,
+    boolean isPrimary,
+    ClassesProcessor.ClassNode node) {
+    this.parameters = parameters;
+    this.flags = flags;
+    this.method = method;
+    this.isPrimary = isPrimary;
+    this.node = node;
+  }
+
+  public static Data parse(ClassesProcessor.ClassNode node) {
+    MetadataNameResolver resolver = KotlinDecompilationContext.getNameResolver();
+    ClassWrapper wrapper = node.getWrapper();
+    StructClass struct = wrapper.getClassStruct();
+
+    KotlinDecompilationContext.KotlinType type = KotlinDecompilationContext.getCurrentType();
+    if (type != KotlinDecompilationContext.KotlinType.CLASS) return null;
+
+    ProtobufFlags.Class classFlags = new ProtobufFlags.Class(KotlinDecompilationContext.getCurrentClass().getFlags());
+    if (classFlags.modality == ProtoBuf.Modality.ABSTRACT) return null;
+
+    List<ProtoBuf.Constructor> protoConstructors = KotlinDecompilationContext.getCurrentClass().getConstructorList();
+    if (protoConstructors.isEmpty()) return null;
+
+    Map<StructMethod, KConstructor> constructors = new HashMap<>();
+    KConstructor primary = null;
+
+    for (ProtoBuf.Constructor constructor : protoConstructors) {
+      KParameter[] parameters = new KParameter[constructor.getValueParameterCount()];
+      for (int i = 0; i < parameters.length; i++) {
+        ProtoBuf.ValueParameter protoParameter = constructor.getValueParameter(i);
+        parameters[i] = new KParameter(
+          new ProtobufFlags.ValueParameter(protoParameter.getFlags()),
+          resolver.resolve(protoParameter.getName()),
+          KType.from(protoParameter.getType(), resolver),
+          KType.from(protoParameter.getVarargElementType(), resolver),
+          protoParameter.getTypeId()
+        );
+      }
+
+      ProtobufFlags.Constructor flags = new ProtobufFlags.Constructor(constructor.getFlags());
+
+      JvmProtoBuf.JvmMethodSignature signature = constructor.getExtension(JvmProtoBuf.constructorSignature);
+      String desc = resolver.resolve(signature.getDesc());
+      MethodWrapper method = wrapper.getMethodWrapper("<init>", desc);
+      if (method == null) {
+        if (classFlags.kind == ProtoBuf.Class.Kind.ANNOTATION_CLASS) {
+          // Annotation classes are very odd and don't actually have a constructor under the hood
+          KConstructor kConstructor = new KConstructor(parameters, flags, null, false, node);
+          return new Data(null, kConstructor);
+        }
+
+        DecompilerContext.getLogger().writeMessage("Method <init>" + desc + " not found in " + struct.qualifiedName, IFernflowerLogger.Severity.WARN);
+        continue;
+      }
+
+      boolean isPrimary = !flags.isSecondary;
+
+      KConstructor kConstructor = new KConstructor(parameters, flags, method, isPrimary, node);
+      constructors.put(method.methodStruct, kConstructor);
+
+      if (isPrimary) {
+        primary = kConstructor;
+      }
+    }
+
+    return new Data(constructors, primary);
+  }
+
+  public boolean stringify(TextBuffer buffer, int indent) {
+    if (KotlinWriter.hideConstructor(node, true, false, parameters.length, method.methodStruct.getAccessFlags())) {
+      return false;
+    }
+
+    TextBuffer buf = new TextBuffer();
+    RootStatement root = method.root;
+
+    if (!isPrimary) {
+      if (flags.hasAnnotations) {
+        KotlinWriter.appendAnnotations(buf, indent, method.methodStruct, TypeAnnotation.METHOD_RETURN_TYPE);
+        KotlinWriter.appendJvmAnnotations(buf, indent, method.methodStruct, false, method.classStruct.getPool(), TypeAnnotation.METHOD_RETURN_TYPE);
+      }
+
+      buf.appendIndent(indent);
+
+      if (flags.visibility != ProtoBuf.Visibility.PUBLIC || DecompilerContext.getOption(KotlinOptions.SHOW_PUBLIC_VISIBILITY)) {
+        KUtils.appendVisibility(buf, flags.visibility);
+      }
+
+      buf.append("constructor");
+
+      buf.append("(").pushNewlineGroup(indent, 1);
+
+      boolean first = true;
+      for (KParameter parameter : parameters) {
+        if (!first) {
+          buf.append(",").appendPossibleNewline(" ");
+        }
+
+        first = false;
+
+        parameter.stringify(indent + 1, buf);
+      }
+
+      buf.appendPossibleNewline("", true).popNewlineGroup().append(") : ");
+
+      Exprent firstExpr = method.getOrBuildGraph().first.exprents.get(0);
+      if (!(firstExpr instanceof InvocationExprent)) {
+        throw new IllegalStateException("First expression of constructor is not InvocationExprent");
+      }
+
+      InvocationExprent invocation = (InvocationExprent) firstExpr;
+      buf.append(invocation.toJava(indent + 1), node.classStruct.qualifiedName, InterpreterUtil.makeUniqueKey(method.methodStruct.getName(), method.methodStruct.getDescriptor()));
+
+      method.getOrBuildGraph().first.exprents.remove(0);
+    }
+
+    if (method.getOrBuildGraph().first.exprents.isEmpty()) {
+      // There is no extra body so all done!
+      if (isPrimary) return false; // avoid extra empty line
+
+      buffer.append(buf);
+      return true;
+    }
+
+    if (isPrimary) {
+      buf.appendIndent(indent).append("init");
+    }
+
+    buf.append(" {").appendLineSeparator();
+
+    TextBuffer body = root.toJava(indent + 1);
+    body.addBytecodeMapping(root.getDummyExit().bytecode);
+
+    StructMethod mt = method.methodStruct;
+    buf.append(body, node.classStruct.qualifiedName, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
+
+    buf.appendIndent(indent).append("}").appendLineSeparator();
+
+    buffer.append(buf);
+    return true;
+  }
+
+  public boolean writePrimaryConstructor(TextBuffer buffer, int indent) {
+    if (!isPrimary) return false;
+
+    TextBuffer buf = new TextBuffer();
+    boolean appended = false;
+
+    if (flags.hasAnnotations) {
+      buf.append(" ");
+      // -1 for indent indicates inline
+      KotlinWriter.appendAnnotations(buf, -1, method.methodStruct, TypeAnnotation.METHOD_RETURN_TYPE);
+      KotlinWriter.appendJvmAnnotations(buf, -1, method.methodStruct, false, method.classStruct.getPool(), TypeAnnotation.METHOD_RETURN_TYPE);
+      appended = true;
+    }
+
+    // For cleanliness, public primary constructors are not forced public by the config option
+    if (flags.visibility != ProtoBuf.Visibility.PUBLIC || (appended && DecompilerContext.getOption(KotlinOptions.SHOW_PUBLIC_VISIBILITY))) {
+      buf.append(" ");
+      KUtils.appendVisibility(buf, flags.visibility);
+      appended = true;
+    }
+
+    if (appended) {
+      buf.append("constructor");
+    }
+
+    if (parameters.length > 0 || appended) {
+      buf.append("(").pushNewlineGroup(indent, 1);
+
+      boolean first = true;
+      for (KParameter parameter : parameters) {
+        if (!first) {
+          buf.append(",").appendPossibleNewline(" ");
+        }
+
+        first = false;
+
+        parameter.stringify(indent + 1, buf);
+      }
+
+      buf.appendPossibleNewline("", true).popNewlineGroup().append(")");
+    }
+
+    RootStatement root = method.root;
+    if (method.getOrBuildGraph().first.exprents.isEmpty()) {
+      // No ability to declare super constructor call
+      buffer.append(buf);
+      return false;
+    }
+
+    Exprent firstExpr = method.getOrBuildGraph().first.exprents.get(0);
+    if (!(firstExpr instanceof InvocationExprent) || !((InvocationExprent) firstExpr).getName().equals("<init>")) {
+      // no detected super constructor call
+      buffer.append(buf);
+      return false;
+//      throw new IllegalStateException("First expression of constructor is not InvocationExprent");
+    }
+
+    InvocationExprent invocation = (InvocationExprent) firstExpr;
+    if (invocation.getClassname().equals("java/lang/Object")) {
+      // No need to declare super constructor call
+      buffer.append(buf);
+      return false;
+    }
+
+    ImportCollector imports = DecompilerContext.getImportCollector();
+    String superClass = imports.getShortName(invocation.getClassname().replace('/', '.'));
+    buf.append(" : ");
+
+    // replace "super" with the actual class name
+    buf.append(superClass).append('(');
+
+    KUtils.removeArguments(invocation, DEFAULT_CONSTRUCTOR_MARKER);
+
+    buf.append(invocation.appendParamList(indent + 1));
+    buf.append(")");
+
+    buf.addBytecodeMapping(invocation.bytecode);
+
+    method.getOrBuildGraph().first.exprents.remove(0);
+
+    buffer.append(buf, node.classStruct.qualifiedName, InterpreterUtil.makeUniqueKey(method.methodStruct.getName(), method.methodStruct.getDescriptor()));
+    return true;
+  }
+
+  public static class Data {
+    public final Map<StructMethod, KConstructor> constructors;
+    public final KConstructor primary;
+
+    public Data(Map<StructMethod, KConstructor> constructors, KConstructor primary) {
+      this.constructors = constructors;
+      this.primary = primary;
+    }
+  }
+}
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KContract.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KContract.java
new file mode 100644
index 0000000000..813361b7aa
--- /dev/null
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KContract.java
@@ -0,0 +1,247 @@
+package org.vineflower.kotlin.struct;
+
+import kotlinx.metadata.internal.metadata.ProtoBuf;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.util.TextBuffer;
+import org.vineflower.kotlin.KotlinWriter;
+import org.vineflower.kotlin.metadata.MetadataNameResolver;
+import org.vineflower.kotlin.util.ProtobufFlags;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class KContract {
+  private static final String INVOCATION_KIND = "kotlin.contracts.InvocationKind";
+  @NotNull
+  public final List<KEffect> effects;
+
+  private KContract(@NotNull List<KEffect> effects) {
+    this.effects = effects;
+  }
+
+  public static KContract from(ProtoBuf.Contract proto, List<KParameter> params, MetadataNameResolver nameResolver) {
+    return new KContract(proto.getEffectList().stream().map(it -> KEffect.from(it, params, nameResolver)).collect(Collectors.toList()));
+  }
+
+  public TextBuffer stringify(int indent) {
+    TextBuffer buf = new TextBuffer();
+    buf.appendIndent(indent).append("contract {").appendLineSeparator();
+    for (KEffect effect : effects) {
+      effect.stringify(buf, indent + 1);
+    }
+    buf.appendIndent(indent).append("}").appendLineSeparator();
+    return buf;
+  }
+
+  public static class KEffect {
+    @Nullable
+    public final ProtoBuf.Effect.EffectType type;
+    @NotNull
+    public final List<KExpression> expressions;
+    @Nullable
+    public final KExpression conditionalConclusion;
+    @Nullable
+    public final ProtoBuf.Effect.InvocationKind kind;
+
+    private KEffect(
+      @Nullable ProtoBuf.Effect.EffectType type,
+      @NotNull List<KExpression> expressions,
+      @Nullable KExpression conditionalConclusion,
+      @Nullable ProtoBuf.Effect.InvocationKind kind) {
+      this.expressions = expressions;
+      this.type = type;
+      this.conditionalConclusion = conditionalConclusion;
+      this.kind = kind;
+    }
+
+    static KEffect from(ProtoBuf.Effect proto, List<KParameter> params, MetadataNameResolver nameResolver) {
+      ProtoBuf.Effect.EffectType type = proto.hasEffectType() ? proto.getEffectType() : null;
+      List<KExpression> expressions = proto.getEffectConstructorArgumentList().stream().map(it -> KExpression.from(it, params, nameResolver)).collect(Collectors.toList());
+      KExpression conditionalConclusion = proto.hasConclusionOfConditionalEffect() ? KExpression.from(proto.getConclusionOfConditionalEffect(), params, nameResolver) : null;
+      ProtoBuf.Effect.InvocationKind kind = proto.hasKind() ? proto.getKind() : null;
+      return new KEffect(type, expressions, conditionalConclusion, kind);
+    }
+
+    public void stringify(TextBuffer buf, int indent) {
+      if (type == null) return;
+
+      buf.appendIndent(indent);
+
+      switch (type) {
+        case RETURNS_NOT_NULL:
+          buf.append("returnsNotNull()");
+          if (conditionalConclusion != null) {
+            buf.append(" implies (");
+            conditionalConclusion.stringify(buf, indent, false);
+            buf.append(')');
+          }
+          break;
+        case CALLS:
+          buf.append("callsInPlace(");
+          KExpression func = expressions.get(0);
+          String name = func.valueParameterReference.name;
+          buf.append(KotlinWriter.toValidKotlinIdentifier(name));
+          if (kind != null) {
+            buf.append(", ")
+              .append(DecompilerContext.getImportCollector().getShortName(INVOCATION_KIND))
+              .append(".")
+              .append(kind.name());
+          }
+          buf.append(")");
+          break;
+        case RETURNS_CONSTANT:
+          buf.append("returns(");
+          if (!expressions.isEmpty()) {
+            KExpression expr = expressions.get(0);
+            expr.stringify(buf, indent, false);
+          }
+          buf.append(")");
+          if (conditionalConclusion != null) {
+            buf.append(" implies (");
+            conditionalConclusion.stringify(buf, indent, false);
+            buf.append(')');
+          }
+          break;
+      }
+      buf.appendLineSeparator();
+    }
+  }
+
+  public static class KExpression {
+    // Placeholder type for receiver type
+    private static final KParameter THIS_TYPE = new KParameter(new ProtobufFlags.ValueParameter(0), "this", KType.NOTHING, null, 0);
+
+    @NotNull
+    public final ProtobufFlags.Expression flags;
+    @Nullable
+    public final KParameter valueParameterReference;
+    @Nullable
+    public final ProtoBuf.Expression.ConstantValue constantValue;
+    @Nullable
+    public final KType instanceofType; // isInstanceType
+    @NotNull
+    public final List<KExpression> andArguments;
+    @NotNull
+    public final List<KExpression> orArguments;
+
+    private KExpression(
+      @NotNull ProtobufFlags.Expression flags,
+      @Nullable KParameter valueParameterReference,
+      @Nullable ProtoBuf.Expression.ConstantValue constantValue,
+      @Nullable KType instanceofType,
+      @NotNull List<KExpression> andArguments,
+      @NotNull List<KExpression> orArguments) {
+      this.flags = flags;
+      this.valueParameterReference = valueParameterReference;
+      this.constantValue = constantValue;
+      this.instanceofType = instanceofType;
+      this.andArguments = andArguments;
+      this.orArguments = orArguments;
+    }
+
+    static KExpression from(ProtoBuf.Expression proto, List<KParameter> params, MetadataNameResolver nameResolver) {
+      ProtobufFlags.Expression flags = new ProtobufFlags.Expression(proto.getFlags());
+      KParameter valueParameterReference = null;
+      if (proto.hasValueParameterReference()) {
+        int index = proto.getValueParameterReference();
+        valueParameterReference = index == 0 ? THIS_TYPE : params.get(index - 1);
+      }
+
+      ProtoBuf.Expression.ConstantValue constantValue = proto.hasConstantValue() ? proto.getConstantValue() : null;
+      KType instanceofType = null;
+      if (proto.hasIsInstanceType()) {
+        instanceofType = KType.from(proto.getIsInstanceType(), nameResolver);
+      } else if (proto.hasIsInstanceTypeId()) {
+        instanceofType = KType.from(proto.getIsInstanceTypeId(), nameResolver);
+      }
+      List<KExpression> andArguments = proto.getAndArgumentList().stream().map(it -> from(it, params, nameResolver)).collect(Collectors.toList());
+      List<KExpression> orArguments = proto.getOrArgumentList().stream().map(it -> from(it, params, nameResolver)).collect(Collectors.toList());
+      return new KExpression(flags, valueParameterReference, constantValue, instanceofType, andArguments, orArguments);
+    }
+
+    public void stringify(TextBuffer buf, int indent, boolean partOfOr) {
+      if (!andArguments.isEmpty() && (!orArguments.isEmpty() || partOfOr)) {
+        // all `&&` predicates must be evaluated before any `||` predicates
+        buf.append('(');
+      }
+
+      boolean appended = true;
+
+      String paramName = null;
+      if (valueParameterReference == THIS_TYPE) {
+        paramName = "this";
+      } else if (valueParameterReference != null) {
+        paramName = KotlinWriter.toValidKotlinIdentifier(valueParameterReference.name);
+      }
+
+      if (instanceofType != null) {
+        buf.append(paramName)
+          .append(' ')
+          .append(flags.isNegated ? "!is" : "is")
+          .append(' ')
+          .append(instanceofType.stringify(indent));
+      } else if (flags.isNullPredicate) {
+        buf.append(paramName)
+          .append(' ')
+          .append(flags.isNegated ? "!=" : "==")
+          .append(' ')
+          .append("null");
+      } else if (constantValue != null) {
+        if (valueParameterReference != null && valueParameterReference.type.isNullable) {
+          buf.append(paramName)
+            .append(' ')
+            .append(flags.isNegated ? "!=" : "==")
+            .append(' ')
+            .append(constantValue.name().toLowerCase());
+        } else {
+          String output = valueParameterReference != null && "kotlin/Boolean".equals(valueParameterReference.type.kotlinType)
+            ? paramName
+            : constantValue.name().toLowerCase();
+
+          if (flags.isNegated) {
+            buf.append('!');
+          }
+
+          buf.append(output);
+        }
+      } else if (valueParameterReference != null) {
+        if (!valueParameterReference.type.kotlinType.equals("kotlin/Boolean")) {
+          //TODO figure out why this happens
+        }
+        if (flags.isNegated) {
+          buf.append('!');
+        }
+        buf.append(paramName);
+      } else {
+        appended = false;
+      }
+
+      if (!andArguments.isEmpty()) {
+        for (KExpression andArgument : andArguments) {
+          if (appended) {
+            buf.append(" && ");
+          }
+          appended = true;
+
+          andArgument.stringify(buf, indent, false);
+        }
+      }
+
+      if (!orArguments.isEmpty()) {
+        if (!andArguments.isEmpty() || partOfOr) {
+          buf.append(')');
+        }
+        for (KExpression orArgument : orArguments) {
+          if (appended) {
+              buf.append(" || ");
+          }
+          appended = true;
+
+          orArgument.stringify(buf, indent, true);
+        }
+      }
+    }
+  }
+}
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KFunction.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KFunction.java
new file mode 100644
index 0000000000..cb4a1c5737
--- /dev/null
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KFunction.java
@@ -0,0 +1,372 @@
+package org.vineflower.kotlin.struct;
+
+import kotlinx.metadata.internal.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.jvm.JvmProtoBuf;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.java.decompiler.main.ClassesProcessor;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.TypeAnnotation;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.TextBuffer;
+import org.vineflower.kotlin.KotlinDecompilationContext;
+import org.vineflower.kotlin.KotlinOptions;
+import org.vineflower.kotlin.KotlinWriter;
+import org.vineflower.kotlin.metadata.MetadataNameResolver;
+import org.vineflower.kotlin.util.KUtils;
+import org.vineflower.kotlin.util.ProtobufFlags;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class KFunction {
+  public final String name;
+  public final ProtobufFlags.Function flags;
+  public final List<KType> contextReceiverTypes;
+  public final KParameter[] parameters;
+  public final List<KTypeParameter> typeParameters;
+  public final KType returnType;
+
+  public final MethodWrapper method;
+
+  @Nullable
+  public final KType receiverType;
+
+  @Nullable
+  public final KContract contract;
+
+  public final boolean knownOverride;
+
+  private final ClassesProcessor.ClassNode node;
+
+  private KFunction(
+    String name,
+    KParameter[] parameters,
+    List<KTypeParameter> typeParameters,
+    KType returnType,
+    ProtobufFlags.Function flags,
+    List<KType> contextReceiverTypes, MethodWrapper method,
+    @Nullable KType receiverType,
+    @Nullable KContract contract,
+    boolean knownOverride,
+    ClassesProcessor.ClassNode node) {
+    this.name = name;
+    this.parameters = parameters;
+    this.typeParameters = typeParameters;
+    this.returnType = returnType;
+    this.flags = flags;
+    this.contextReceiverTypes = contextReceiverTypes;
+    this.method = method;
+    this.receiverType = receiverType;
+    this.contract = contract;
+    this.knownOverride = knownOverride;
+    this.node = node;
+  }
+
+  public static Map<StructMethod, KFunction> parse(ClassesProcessor.ClassNode node) {
+    MetadataNameResolver resolver = KotlinDecompilationContext.getNameResolver();
+    ClassWrapper wrapper = node.getWrapper();
+    StructClass struct = wrapper.getClassStruct();
+
+    List<ProtoBuf.Function> protoFunctions;
+
+    KotlinDecompilationContext.KotlinType type = KotlinDecompilationContext.getCurrentType();
+    if (type == null) return Map.of();
+
+    switch (type) {
+      case CLASS:
+        protoFunctions = KotlinDecompilationContext.getCurrentClass().getFunctionList();
+        break;
+      case FILE:
+        protoFunctions = KotlinDecompilationContext.getFilePackage().getFunctionList();
+        break;
+      case MULTIFILE_CLASS:
+        protoFunctions = KotlinDecompilationContext.getMultifilePackage().getFunctionList();
+        break;
+      case SYNTHETIC_CLASS:
+        // indicating lambdas and such
+        protoFunctions = Collections.singletonList(KotlinDecompilationContext.getSyntheticClass());
+        break;
+      default:
+        throw new IllegalStateException("Unexpected value: " + type);
+    }
+
+    Map<StructMethod, KFunction> functions = new HashMap<>(protoFunctions.size(), 1f);
+
+    for (ProtoBuf.Function function : protoFunctions) {
+      JvmProtoBuf.JvmMethodSignature jvmData = function.getExtension(JvmProtoBuf.methodSignature);
+
+      ProtobufFlags.Function flags = new ProtobufFlags.Function(function.getFlags());
+
+      String name = resolver.resolve(function.getName());
+
+      KParameter[] parameters = new KParameter[function.getValueParameterCount()];
+      for (int i = 0; i < parameters.length; i++) {
+        ProtoBuf.ValueParameter parameter = function.getValueParameter(i);
+        ProtobufFlags.ValueParameter paramFlags = new ProtobufFlags.ValueParameter(parameter.getFlags());
+        String paramName = resolver.resolve(parameter.getName());
+        KType paramType = KType.from(parameter.getType(), resolver);
+        KType varargType = parameter.hasVarargElementType() ? KType.from(parameter.getVarargElementType(), resolver) : null;
+        int typeId = parameter.getTypeId();
+        parameters[i] = new KParameter(paramFlags, paramName, paramType, varargType, typeId);
+      }
+
+      KType receiverType = null;
+      if (function.hasReceiverType()) {
+        receiverType = KType.from(function.getReceiverType(), resolver);
+      }
+
+      KType returnType = KType.from(function.getReturnType(), resolver);
+
+      MethodWrapper method = null;
+
+      if (jvmData.hasDesc()) {
+        String lookupName = jvmData.hasName() ? resolver.resolve(jvmData.getName()) : name;
+        method = wrapper.getMethodWrapper(lookupName, resolver.resolve(jvmData.getDesc()));
+      }
+
+      if (method == null) {
+        StringBuilder desc = new StringBuilder("(");
+        if (receiverType != null) {
+          desc.append(receiverType);
+        }
+
+        for (KParameter parameter : parameters) {
+          desc.append(parameter.type);
+        }
+
+        int endOfParams = desc.length();
+        desc.append(")").append(returnType);
+
+        method = wrapper.getMethodWrapper(name, desc.toString());
+
+        if (method == null) {
+          throw new IllegalStateException("Couldn't find method " + name + " " + desc + " in class " + struct.qualifiedName);
+        }
+      }
+
+      List<KTypeParameter> typeParameters = function.getTypeParameterList().stream()
+        .map(typeParameter -> KTypeParameter.from(typeParameter, resolver))
+        .collect(Collectors.toList());
+
+      List<KType> contextReceiverTypes = function.getContextReceiverTypeList().stream()
+        .map(ctxType -> KType.from(ctxType, resolver))
+        .collect(Collectors.toList());
+
+      boolean knownOverride = flags.visibility != ProtoBuf.Visibility.PRIVATE
+        && flags.visibility != ProtoBuf.Visibility.PRIVATE_TO_THIS
+        && flags.visibility != ProtoBuf.Visibility.LOCAL
+        && KotlinWriter.searchForMethod(struct, method.methodStruct.getName(), method.desc(), false);
+
+      KContract contract = function.hasContract() ? KContract.from(function.getContract(), List.of(parameters), resolver) : null;
+
+      functions.put(method.methodStruct, new KFunction(name, parameters, typeParameters, returnType, flags, contextReceiverTypes, method, receiverType, contract, knownOverride, node));
+    }
+
+    return functions;
+  }
+
+  public TextBuffer stringify(int indent) {
+    TextBuffer buf = new TextBuffer();
+    KotlinWriter.appendAnnotations(buf, indent, method.methodStruct, TypeAnnotation.METHOD_RETURN_TYPE);
+    KotlinWriter.appendJvmAnnotations(buf, indent, method.methodStruct, false, method.classStruct.getPool(), TypeAnnotation.METHOD_RETURN_TYPE);
+
+    buf.appendIndent(indent);
+
+    if (!contextReceiverTypes.isEmpty()) {
+      buf.append("context(");
+      boolean first = true;
+      for (KType contextReceiverType : contextReceiverTypes) {
+        if (!first) {
+          buf.append(", ");
+        }
+
+        buf.append(contextReceiverType.stringify(indent + 1));
+        first = false;
+      }
+      buf.append(")").appendLineSeparator().appendIndent(indent);
+    }
+
+    if (flags.visibility != ProtoBuf.Visibility.PUBLIC || DecompilerContext.getOption(KotlinOptions.SHOW_PUBLIC_VISIBILITY)) {
+      KUtils.appendVisibility(buf, flags.visibility);
+    }
+
+    if (flags.isExpect) {
+      buf.append("expect ");
+    }
+
+    if (flags.modality != ProtoBuf.Modality.FINAL) {
+      if (!knownOverride || flags.modality != ProtoBuf.Modality.OPEN) {
+        buf.append(flags.modality.name().toLowerCase())
+          .append(' ');
+      }
+    }
+
+    if (flags.isExternal) {
+      buf.append("external ");
+    }
+
+    if (knownOverride) {
+      buf.append("override ");
+    }
+
+    if (flags.isTailrec) {
+      buf.append("tailrec ");
+    }
+
+    if (flags.isSuspend) {
+      buf.append("suspend ");
+    }
+
+    if (flags.isInline) {
+      buf.append("inline ");
+    }
+
+    if (flags.isInfix) {
+      buf.append("infix ");
+    }
+
+    if (flags.isOperator) {
+      buf.append("operator ");
+    }
+
+    buf.append("fun ");
+
+    List<KTypeParameter> complexTypeParams = typeParameters.stream()
+      .filter(typeParameter -> typeParameter.upperBounds.size() > 1)
+      .collect(Collectors.toList());
+
+    Map<Integer, KTypeParameter> typeParamsById = typeParameters.stream()
+      .collect(Collectors.toMap(typeParameter -> typeParameter.id, Function.identity()));
+
+    if (!typeParameters.isEmpty()) {
+      buf.append('<');
+
+      for (int i = 0; i < typeParameters.size(); i++) {
+        KTypeParameter typeParameter = typeParameters.get(i);
+
+        if (typeParameter.reified) {
+          buf.append("reified ");
+        }
+
+        buf.append(KotlinWriter.toValidKotlinIdentifier(typeParameter.name));
+
+        if (typeParameter.upperBounds.size() == 1) {
+          buf.append(" : ").append(typeParameter.upperBounds.get(0).stringify(indent + 1));
+        }
+
+        if (i < typeParameters.size() - 1) {
+          buf.append(", ");
+        }
+      }
+
+      buf.append("> ");
+    }
+
+    if (receiverType != null) {
+      // Function types need parentheses around the receiver type, but that happens in KType.stringify only if it's nullable
+      // so we need to wrap in the case of non-nullable function types
+      if (!receiverType.isNullable && receiverType.kotlinType.startsWith("kotlin/Function")) {
+        buf.append("(");
+      }
+      buf.append(receiverType.stringify(indent + 1));
+      if (!receiverType.isNullable && receiverType.kotlinType.startsWith("kotlin/Function")) {
+        buf.append(")");
+      }
+
+      buf.append(".");
+    }
+
+    buf.append(KotlinWriter.toValidKotlinIdentifier(name))
+      .append('(')
+      .pushNewlineGroup(indent, 1)
+      .appendPossibleNewline("");
+
+    boolean first = true;
+    for (KParameter parameter : parameters) {
+      if (!first) {
+        buf.append(",").appendPossibleNewline(" ");
+      }
+
+      first = false;
+
+      parameter.stringify(indent + 1, buf);
+    }
+
+    buf.appendPossibleNewline("", true)
+      .popNewlineGroup()
+      .append(')');
+
+    if (returnType != null && returnType.type != VarType.VARTYPE_VOID.type) {
+      buf.append(": ")
+        .append(returnType.stringify(indent + 1));
+    }
+
+    if (complexTypeParams.isEmpty()) {
+      buf.append(' ');
+    } else {
+      buf.pushNewlineGroup(indent, 1)
+        .appendPossibleNewline(" ")
+        .append("where ");
+
+      first = true;
+      for (KTypeParameter typeParameter : complexTypeParams) {
+        for (KType upperBound : typeParameter.upperBounds) {
+          if (!first) {
+            buf.appendPossibleNewline(",").appendPossibleNewline(" ");
+          }
+
+          buf.append(KotlinWriter.toValidKotlinIdentifier(typeParameter.name))
+            .append(" : ")
+            .append(upperBound.stringify(indent + 1));
+
+          first = false;
+        }
+      }
+
+      buf.appendPossibleNewline(" ", true)
+        .popNewlineGroup();
+    }
+
+    buf.append('{').appendLineSeparator();
+
+    if (contract != null) {
+      buf.append(contract.stringify(indent + 1));
+    }
+
+    RootStatement root = method.root;
+    if (root != null && method.decompileError == null) {
+      try {
+        TextBuffer body = root.toJava(indent + 1);
+        body.addBytecodeMapping(root.getDummyExit().bytecode);
+        if (body.length() != 0 && contract != null) {
+          buf.appendLineSeparator();
+        }
+
+        buf.append(body, node.classStruct.qualifiedName, InterpreterUtil.makeUniqueKey(method.methodStruct.getName(), method.methodStruct.getDescriptor()));
+      } catch (Throwable t) {
+        String message = "Method " + method.methodStruct.getName() + " " + method.desc() + " in class " + node.classStruct.qualifiedName + " couldn't be written.";
+        DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN, t);
+        method.decompileError = t;
+      }
+    }
+
+    if (method.decompileError != null) {
+      KotlinWriter.dumpError(buf, method, indent + 1);
+    }
+
+    buf.appendIndent(indent).append('}').appendLineSeparator();
+
+    return buf;
+  }
+}
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KParameter.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KParameter.java
new file mode 100644
index 0000000000..cd4eb4af9b
--- /dev/null
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KParameter.java
@@ -0,0 +1,43 @@
+package org.vineflower.kotlin.struct;
+
+import org.jetbrains.java.decompiler.util.TextBuffer;
+import org.vineflower.kotlin.KotlinWriter;
+import org.vineflower.kotlin.util.ProtobufFlags;
+
+public class KParameter {
+  public final ProtobufFlags.ValueParameter flags;
+  public final String name;
+  public final KType type;
+  public final KType varargType;
+  public final int typeId;
+
+  KParameter(ProtobufFlags.ValueParameter flags, String name, KType type, KType varargType, int typeId) {
+    this.flags = flags;
+    this.name = name;
+    this.type = type;
+    this.varargType = varargType;
+    this.typeId = typeId;
+  }
+
+  public void stringify(int indent, TextBuffer buf) {
+    if (flags.isCrossinline) {
+      buf.append("crossinline ");
+    }
+
+    if (flags.isNoinline) {
+      buf.append("noinline ");
+    }
+
+    // Vararg types are a bit odd to say the least
+    boolean isVararg = varargType != null && type.kotlinType.equals("kotlin/Array");
+
+    if (isVararg) {
+      buf.append("vararg ");
+    }
+
+    buf.append(KotlinWriter.toValidKotlinIdentifier(name)).append(": ");
+
+    KType type = isVararg ? varargType : this.type;
+    buf.append(type.stringify(indent + 1));
+  }
+}
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KProperty.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KProperty.java
index cbcb379179..0808b07627 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KProperty.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KProperty.java
@@ -1,7 +1,7 @@
 package org.vineflower.kotlin.struct;
 
-import kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf;
-import kotlin.reflect.jvm.internal.impl.metadata.jvm.JvmProtoBuf;
+import kotlinx.metadata.internal.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.jvm.JvmProtoBuf;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.java.decompiler.code.CodeConstants;
 import org.jetbrains.java.decompiler.main.ClassesProcessor;
@@ -25,6 +25,7 @@
 import org.vineflower.kotlin.KotlinWriter;
 import org.vineflower.kotlin.metadata.MetadataNameResolver;
 import org.vineflower.kotlin.util.KTypes;
+import org.vineflower.kotlin.util.KUtils;
 import org.vineflower.kotlin.util.ProtobufFlags;
 
 import java.util.*;
@@ -78,7 +79,7 @@ public TextBuffer stringify(int indent) {
     buf.appendIndent(indent);
 
     // Modifiers in the order that Kotlin's coding conventions specify
-    appendVisibility(buf, flags.visibility);
+    KUtils.appendVisibility(buf, flags.visibility);
 
     if (flags.isExpect) {
       buf.append("expect ");
@@ -122,10 +123,10 @@ public TextBuffer stringify(int indent) {
     // Custom getters and setters, and possible modifier differences
     if (getter != null && getter.flags.isNotDefault) {
       buf.pushNewlineGroup(indent, 1)
-          .append('\n')
+          .appendLineSeparator()
           .appendIndent(indent + 1);
 
-      appendVisibility(buf, getter.flags.visibility);
+      KUtils.appendVisibility(buf, getter.flags.visibility);
 
       buf.append(getter.flags.modality.name().toLowerCase())
         .append(' ');
@@ -144,17 +145,17 @@ public TextBuffer stringify(int indent) {
 
       buf.popNewlineGroup();
     } else if (getter != null && getter.flags.isExternal) {
-      buf.append('\n')
+      buf.appendLineSeparator()
         .appendIndent(indent + 1)
         .append("external get");
     }
 
     if (setter != null && setter.flags.isNotDefault) {
       buf.pushNewlineGroup(indent, 1)
-        .append('\n')
+        .appendLineSeparator()
         .appendIndent(indent + 1);
 
-      appendVisibility(buf, getter.flags.visibility);
+      KUtils.appendVisibility(buf, getter.flags.visibility);
 
       buf.append(setter.flags.modality.name().toLowerCase())
         .append(' ');
@@ -175,10 +176,10 @@ public TextBuffer stringify(int indent) {
 
       buf.popNewlineGroup();
     } else if (setter != null && (setter.flags.isExternal || setter.flags.visibility != flags.visibility || setter.flags.modality != flags.modality)) {
-      buf.append('\n').appendIndent(indent + 1);
+      buf.appendLineSeparator().appendIndent(indent + 1);
 
       if (setter.flags.visibility != flags.visibility) {
-        appendVisibility(buf, setter.flags.visibility);
+        KUtils.appendVisibility(buf, setter.flags.visibility);
       }
 
       if (setter.flags.modality != flags.modality) {
@@ -192,7 +193,7 @@ public TextBuffer stringify(int indent) {
 
       buf.append("set");
     } else if (setter == null && flags.isVar && flags.visibility != ProtoBuf.Visibility.PRIVATE) { // Special case: no setter is generated if it's a var with a private setter
-      buf.append('\n')
+      buf.appendLineSeparator()
         .appendIndent(indent + 1)
         .append("private set");
     }
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KType.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KType.java
index d0951ef354..5d6f4728bb 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KType.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KType.java
@@ -1,31 +1,58 @@
 package org.vineflower.kotlin.struct;
 
-import kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.ProtoBuf;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
 import org.jetbrains.java.decompiler.struct.gen.VarType;
 import org.jetbrains.java.decompiler.util.TextBuffer;
+import org.vineflower.kotlin.KotlinDecompilationContext;
 import org.vineflower.kotlin.metadata.MetadataNameResolver;
 import org.vineflower.kotlin.util.KTypes;
 
+import java.util.Objects;
+
 public class KType extends VarType {
-  public final String kotlinType;
+  public static final KType UNIT = new KType(VARTYPE_VOID, "kotlin/Unit", false, null, null, null);
+  public static final KType NOTHING = new KType(new VarType("java/lang/Void", true), "kotlin/Nothing", false, null, null, null);
 
+  public final String kotlinType;
   public final boolean isNullable;
-
   public final TypeArgument @Nullable [] typeArguments;
 
-  public KType(VarType type, String kotlinType, boolean isNullable, TypeArgument @Nullable [] typeArguments) {
+  @Nullable
+  public final String typeParameterName;
+
+  @Nullable
+  public final String typeAliasName;
+
+  private KType(
+    VarType type,
+    String kotlinType,
+    boolean isNullable,
+    TypeArgument @Nullable [] typeArguments,
+    @Nullable String typeParameterName,
+    @Nullable String typeAliasName) {
     super(type.type, type.arrayDim, type.value, type.typeFamily, type.stackSize);
     this.kotlinType = kotlinType;
     this.isNullable = isNullable;
     this.typeArguments = typeArguments;
+    this.typeParameterName = typeParameterName;
+    this.typeAliasName = typeAliasName;
   }
   
   public static KType from(ProtoBuf.Type type, MetadataNameResolver nameResolver) {
-    String kotlinType = nameResolver.resolve(type.getClassName());
+    String kotlinType = type.hasClassName() ? nameResolver.resolve(type.getClassName()) : "kotlin/Any";
     boolean isNullable = type.getNullable();
-    String jvmDesc = KTypes.getJavaSignature(kotlinType, isNullable);
-    VarType varType = new VarType(jvmDesc);
+
+    // short-circuit for `Unit`
+    if ("kotlin/Unit".equals(kotlinType) && !isNullable) {
+      return UNIT;
+    }
+
+    // similar short-circuit for `Nothing`
+    if ("kotlin/Nothing".equals(kotlinType) && !isNullable) {
+      return NOTHING;
+    }
 
     TypeArgument[] typeArguments = null;
     if (type.getArgumentCount() > 0) {
@@ -36,14 +63,61 @@ public static KType from(ProtoBuf.Type type, MetadataNameResolver nameResolver)
       }
     }
 
-    return new KType(varType, kotlinType, isNullable, typeArguments);
+    String jvmDesc = KTypes.getJavaSignature(kotlinType, isNullable);
+    if ("kotlin/Array".equals(kotlinType)) {
+      TypeArgument arrayType = Objects.requireNonNull(typeArguments)[0];
+      if (arrayType.typeProjection == ProtoBuf.Type.Argument.Projection.IN) {
+        jvmDesc = "[Ljava/lang/Object;"; // `in` variance is erased to `Object` (to allow any supertype to be passed in)
+      } else {
+        jvmDesc = "[" + arrayType.type.toString();
+      }
+    }
+    VarType varType = new VarType(jvmDesc);
+
+    String typeParameterName = type.hasTypeParameterName() ? nameResolver.resolve(type.getTypeParameterName()) : null;
+    String typeAliasName = type.hasTypeAliasName() ? nameResolver.resolve(type.getTypeAliasName()) : null;
+
+    return new KType(varType, kotlinType, isNullable, typeArguments, typeParameterName, typeAliasName);
+  }
+
+  public static KType from(int tableIndex, MetadataNameResolver resolver) {
+    ProtoBuf.TypeTable table;
+    switch (KotlinDecompilationContext.getCurrentType()) {
+      case CLASS:
+        table = KotlinDecompilationContext.getCurrentClass().getTypeTable();
+        break;
+      case SYNTHETIC_CLASS:
+        table = KotlinDecompilationContext.getSyntheticClass().getTypeTable();
+        break;
+      case FILE:
+        table = KotlinDecompilationContext.getFilePackage().getTypeTable();
+        break;
+      case MULTIFILE_CLASS:
+        table = KotlinDecompilationContext.getMultifilePackage().getTypeTable();
+        break;
+      default:
+        throw new IllegalStateException("No decompilation context found");
+    }
+
+    return from(table.getType(tableIndex), resolver);
   }
 
+  // stringify is for the decompiler output
   public TextBuffer stringify(int indent) {
     TextBuffer buf = new TextBuffer();
 
+    if (typeParameterName != null) {
+      buf.append(typeParameterName);
+      if (isNullable) {
+        buf.append("?");
+      }
+
+      return buf;
+    }
+
     if (!kotlinType.startsWith("kotlin/Function")) { // Non-functions are essentially equivalent to Java generic types
-      buf.append(KTypes.getKotlinType(this));
+      String type = kotlinType.replace('/', '.');
+      buf.append(DecompilerContext.getImportCollector().getShortName(type));
 
       if (typeArguments != null) {
         buf.append("<");
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KTypeParameter.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KTypeParameter.java
new file mode 100644
index 0000000000..e802a58088
--- /dev/null
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/struct/KTypeParameter.java
@@ -0,0 +1,38 @@
+package org.vineflower.kotlin.struct;
+
+import kotlinx.metadata.internal.metadata.ProtoBuf;
+import org.vineflower.kotlin.metadata.MetadataNameResolver;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class KTypeParameter {
+  public final boolean reified;
+  public final ProtoBuf.TypeParameter.Variance variance;
+  public final List<KType> upperBounds;
+  public final String name;
+  public final int id;
+
+  private KTypeParameter(
+    boolean reified,
+    ProtoBuf.TypeParameter.Variance variance,
+    List<KType> upperBounds,
+    String name,
+    int id) {
+    this.reified = reified;
+    this.variance = variance;
+    this.upperBounds = upperBounds;
+    this.name = name;
+    this.id = id;
+  }
+
+  public static KTypeParameter from(ProtoBuf.TypeParameter proto, MetadataNameResolver resolver) {
+    return new KTypeParameter(
+      proto.getReified(),
+      proto.getVariance(),
+      proto.getUpperBoundList().stream().map(type -> KType.from(type, resolver)).collect(Collectors.toList()),
+      resolver.resolve(proto.getName()),
+      proto.getId()
+    );
+  }
+}
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/KTypes.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/KTypes.java
index 63e4530ec6..05e43a3144 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/KTypes.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/KTypes.java
@@ -29,29 +29,36 @@ public final class KTypes {
     "java/util/Collection", "MutableCollection",
     "java/util/Iterator", "MutableIterator",
     "java/util/Map$Entry", "MutableMap.MutableEntry",
-    "java/util/Iterable", "MutableIterable"
+    "java/lang/Iterable", "MutableIterable"
   );
   
-  private static final Map<String, String> KOTLIN_TO_JAVA_LANG = Map.of(
-    "kotlin/Int", "java/lang/Integer",
-    "kotlin/Long", "java/lang/Long",
-    "kotlin/Short", "java/lang/Short",
-    "kotlin/Byte", "java/lang/Byte",
-    "kotlin/Boolean", "java/lang/Boolean",
-    "kotlin/Char", "java/lang/Character",
-    "kotlin/Float", "java/lang/Float",
-    "kotlin/Double", "java/lang/Double",
-    "kotlin/String", "java/lang/String",
-    "kotlin/Any", "java/lang/Object"
+  public static final Map<String, String> KOTLIN_TO_JAVA_LANG = Map.ofEntries(
+    Map.entry("kotlin/Any", "java/lang/Object"),
+    Map.entry("kotlin/Boolean", "java/lang/Boolean"),
+    Map.entry("kotlin/Byte", "java/lang/Byte"),
+    Map.entry("kotlin/Char", "java/lang/Character"),
+    Map.entry("kotlin/CharSequence", "java/lang/CharSequence"),
+    Map.entry("kotlin/Comparable", "java/lang/Comparable"),
+    Map.entry("kotlin/Double", "java/lang/Double"),
+    Map.entry("kotlin/Enum", "java/lang/Enum"),
+    Map.entry("kotlin/Float", "java/lang/Float"),
+    Map.entry("kotlin/Int", "java/lang/Integer"),
+    Map.entry("kotlin/Long", "java/lang/Long"),
+    Map.entry("kotlin/Nothing", "java/lang/Void"),
+    Map.entry("kotlin/Number", "java/lang/Number"),
+    Map.entry("kotlin/Short", "java/lang/Short"),
+    Map.entry("kotlin/String", "java/lang/String"),
+    Map.entry("kotlin/Throwable", "java/lang/Throwable"),
+    Map.entry("kotlin/collections/MutableIterable", "java/lang/Iterable"),
+    Map.entry("kotlin/collections/Iterable", "java/lang/Iterable")
   );
 
-  private static final Map<String, String> KOTLIN_TO_JAVA_UTIL = Map.of(
+  public static final Map<String, String> KOTLIN_TO_JAVA_UTIL = Map.of(
     "kotlin/collections/MutableMap", "java/util/Map",
     "kotlin/collections/MutableList", "java/util/List",
     "kotlin/collections/MutableSet", "java/util/Set",
     "kotlin/collections/MutableIterator", "java/util/Iterator",
-    "kotlin/collections/MutableIterable", "java/util/Iterable",
-    "kotlin/collections/MutableMap.MutableEntry", "java/util/Map$Entry"
+    "kotlin/collections/MutableMap$MutableEntry", "java/util/Map$Entry"
   );
   
   private static final Map<String, String> KOTLIN_PRIMITIVE_TYPES = Map.of(
@@ -71,9 +78,18 @@ public static String getJavaSignature(String kotlinType, boolean isNullable) {
       kotlinType = kotlinType.substring(1, kotlinType.length() - 1);
     }
 
+    // Kotlin uses . instead of $ when referring to inner classes in metadata but keeps $ in the bytecode
+    if (kotlinType.contains(".")) {
+      kotlinType = kotlinType.replace('.', '$');
+    }
+
     if (kotlinType.startsWith("kotlin/")) {
       if (KOTLIN_PRIMITIVE_TYPES.containsKey(kotlinType) && !isNullable) {
         return KOTLIN_PRIMITIVE_TYPES.get(kotlinType);
+      } else if (kotlinType.endsWith("$Companion") && KOTLIN_PRIMITIVE_TYPES.containsKey(kotlinType.replace("$Companion", ""))) {
+        return "Lkotlin/jvm/internal/" + kotlinType.split("/")[1].split("\\$")[0] + "CompanionObject;";
+      } else if (kotlinType.endsWith("Array") && KOTLIN_PRIMITIVE_TYPES.containsKey(kotlinType.replace("Array", ""))) {
+        return "[" + KOTLIN_PRIMITIVE_TYPES.get(kotlinType.replace("Array", ""));
       } else if (KOTLIN_TO_JAVA_LANG.containsKey(kotlinType)) {
         return "L" + KOTLIN_TO_JAVA_LANG.get(kotlinType) + ";";
       } else if (KOTLIN_TO_JAVA_UTIL.containsKey(kotlinType)) {
@@ -97,6 +113,11 @@ public static String getKotlinType(VarType type) {
   }
 
   public static String getKotlinType(VarType type, boolean includeOuterClasses) {
+    if (type == null) {
+      //TODO: prevent passing null
+      return "*";
+    }
+
     String typeStr;
     if (isFunctionType(type)) {
       typeStr = functionTypeToKotlin(type);
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/KUtils.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/KUtils.java
index 042546c9fc..ca0879d7d2 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/KUtils.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/KUtils.java
@@ -1,10 +1,16 @@
 package org.vineflower.kotlin.util;
 
+import kotlinx.metadata.internal.metadata.ProtoBuf;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
 import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.TextBuffer;
+import org.vineflower.kotlin.KotlinOptions;
 import org.vineflower.kotlin.expr.*;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 public class KUtils {
   public static List<? extends Exprent> replaceExprents(List<? extends Exprent> exprs) {
@@ -39,4 +45,66 @@ public static Exprent replaceExprent(Exprent ex) {
 
     return null;
   }
+
+  public static void appendVisibility(TextBuffer buf, ProtoBuf.Visibility visibility) {
+    switch (visibility) {
+      case LOCAL:
+        buf.append("// QF: local property")
+          .appendLineSeparator()
+          .append("internal ");
+        break;
+      case PRIVATE_TO_THIS:
+        buf.append("private ");
+        break;
+      case PUBLIC:
+        if (DecompilerContext.getOption(KotlinOptions.SHOW_PUBLIC_VISIBILITY)) {
+          buf.append("public ");
+        }
+        break;
+      default:
+        buf.append(visibility.name().toLowerCase())
+          .append(' ');
+    }
+  }
+
+  public static void removeArguments(InvocationExprent expr, VarType toRemove) {
+    removeArguments(expr, toRemove, null);
+  }
+
+  public static void removeArguments(InvocationExprent expr, VarType toRemove, VarType replaceReturnType) {
+    if (expr.getLstParameters().isEmpty()) {
+      return;
+    }
+
+    if (expr.getLstParameters().size() == 1) {
+      VarType argType = expr.getDescriptor().params[0];
+      if (argType.equals(toRemove)) {
+        expr.getLstParameters().clear();
+      }
+      return;
+    }
+
+    VarType[] params = expr.getDescriptor().params;
+    List<Exprent> lst = expr.getLstParameters();
+    for (int i = 0; i < params.length; i++) {
+      VarType argType = params[i];
+      if (argType.equals(toRemove)) {
+        lst.set(i, null);
+      }
+    }
+    lst.removeIf(Objects::isNull);
+
+    String newDesc = expr.getStringDescriptor()
+      .replace(toRemove.toString(), "");
+
+      if (newDesc.endsWith(")")) {
+        if (replaceReturnType == null) {
+          throw new IllegalStateException("Invalid descriptor: " + newDesc);
+        }
+
+        newDesc += replaceReturnType.toString();
+      }
+
+    expr.setStringDescriptor(newDesc);
+  }
 }
diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/ProtobufFlags.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/ProtobufFlags.java
index 37a43dcf08..8a32ad4edf 100644
--- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/ProtobufFlags.java
+++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/util/ProtobufFlags.java
@@ -1,9 +1,11 @@
 package org.vineflower.kotlin.util;
 
-import kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.ProtoBuf;
+import kotlinx.metadata.internal.metadata.deserialization.Flags;
 
 public interface ProtobufFlags {
   //TODO: hasNonStableParameterNames
+  //TODO: Update everything to use Flags class
 
   int HAS_ANNOTATIONS = 0x0001;
 
@@ -207,6 +209,18 @@ public Class(int flags) {
   }
   //endregion
 
+  //region: Contract
+  class Expression {
+    public final boolean isNegated;
+    public final boolean isNullPredicate;
+
+    public Expression(int flags) {
+      isNegated = Flags.IS_NEGATED.get(flags);
+      isNullPredicate = Flags.IS_NULL_CHECK_PREDICATE.get(flags);
+    }
+  }
+  //endregion
+
   static String toString(ProtoBuf.Visibility visibility) {
     switch (visibility) {
       case PRIVATE:
diff --git a/plugins/kotlin/src/test/java/org/vineflower/kotlin/KotlinTests.java b/plugins/kotlin/src/test/java/org/vineflower/kotlin/KotlinTests.java
index 6a8c372a86..cb6d438fa3 100644
--- a/plugins/kotlin/src/test/java/org/vineflower/kotlin/KotlinTests.java
+++ b/plugins/kotlin/src/test/java/org/vineflower/kotlin/KotlinTests.java
@@ -84,5 +84,6 @@ private void registerKotlinTests() {
     register(KOTLIN, "TestSynchronized");
     register(KOTLIN, "TestReflection");
     register(KOTLIN, "TestConstructors");
+    register(KOTLIN, "TestContracts");
   }
 }
diff --git a/plugins/kotlin/testData/results/pkg/TestAnnotations.dec b/plugins/kotlin/testData/results/pkg/TestAnnotations.dec
index 94bc96cd03..9fea29d521 100644
--- a/plugins/kotlin/testData/results/pkg/TestAnnotations.dec
+++ b/plugins/kotlin/testData/results/pkg/TestAnnotations.dec
@@ -2,29 +2,21 @@ package pkg
 
 import java.lang.annotation.Retention
 import java.lang.annotation.RetentionPolicy
-import kotlin.jvm.internal.RepeatableContainer
 
 class TestAnnotations {
    @TestAnnotations.TestAnnotation(first = "test", second = 1)
-   fun test() {
+   public fun test() {
    }// 16
 
    @TestAnnotations.RepeatableAnnotation.Container([@TestAnnotations.RepeatableAnnotation("test"), @TestAnnotations.RepeatableAnnotation("test2")])
-   fun test2() {
+   public fun test2() {
    }// 21
 
    @Repeatable
    @Retention(RetentionPolicy.RUNTIME)
-   @java.lang.annotation.Repeatable(TestAnnotations.RepeatableAnnotation.Container::class)
    annotation class RepeatableAnnotation(
       val value: String
-   ) {
-      @RepeatableContainer
-      @Retention(RetentionPolicy.RUNTIME)
-      annotation class Container(
-         val value: Array<TestAnnotations.RepeatableAnnotation>
-      )
-   }
+   )
 
    @Retention(RetentionPolicy.RUNTIME)
    annotation class TestAnnotation(
@@ -35,14 +27,14 @@ class TestAnnotations {
 
 class 'pkg/TestAnnotations' {
    method 'test ()V' {
-      0      9
+      0      8
    }
 
    method 'test2 ()V' {
-      0      13
+      0      12
    }
 }
 
 Lines mapping:
-16 <-> 10
-21 <-> 14
+16 <-> 9
+21 <-> 13
diff --git a/plugins/kotlin/testData/results/pkg/TestAnyType.dec b/plugins/kotlin/testData/results/pkg/TestAnyType.dec
index 1d00d4bba4..40e0f17498 100644
--- a/plugins/kotlin/testData/results/pkg/TestAnyType.dec
+++ b/plugins/kotlin/testData/results/pkg/TestAnyType.dec
@@ -1,9 +1,9 @@
 package pkg
 
 class TestAnyType {
-   fun test(param: Any): Int {
-      if (param is String) {// 5
-         return (param as String).length();// 6
+   public fun test(param: Any): Int {
+      if (param is java.lang.String) {// 5
+         return (param as java.lang.String).length();// 6
       } else {
          System.out.println(param);// 9
          return 0;// 11
diff --git a/plugins/kotlin/testData/results/pkg/TestBitwiseFunctions.dec b/plugins/kotlin/testData/results/pkg/TestBitwiseFunctions.dec
index 59ca9dc8d6..ecec103da9 100644
--- a/plugins/kotlin/testData/results/pkg/TestBitwiseFunctions.dec
+++ b/plugins/kotlin/testData/results/pkg/TestBitwiseFunctions.dec
@@ -1,27 +1,27 @@
 package pkg
 
 class TestBitwiseFunctions {
-   fun and(a: Int, b: Int): Int {
+   public fun and(a: Int, b: Int): Int {
       return a and b;// 5
    }
 
-   fun or(a: Int, b: Int): Int {
+   public fun or(a: Int, b: Int): Int {
       return a or b;// 9
    }
 
-   fun xor(a: Int, b: Int): Int {
+   public fun xor(a: Int, b: Int): Int {
       return a xor b;// 13
    }
 
-   fun shl(a: Int, b: Int): Int {
+   public fun shl(a: Int, b: Int): Int {
       return a shl b;// 17
    }
 
-   fun shr(a: Int, b: Int): Int {
+   public fun shr(a: Int, b: Int): Int {
       return a shr b;// 21
    }
 
-   fun ushr(a: Int, b: Int): Int {
+   public fun ushr(a: Int, b: Int): Int {
       return a ushr b;// 25
    }
 }
diff --git a/plugins/kotlin/testData/results/pkg/TestClassDec.dec b/plugins/kotlin/testData/results/pkg/TestClassDec.dec
index 0e0774fa9d..05fc5b7a6b 100644
--- a/plugins/kotlin/testData/results/pkg/TestClassDec.dec
+++ b/plugins/kotlin/testData/results/pkg/TestClassDec.dec
@@ -1,11 +1,11 @@
 package pkg
 
 class TestClassDec {
-   fun TestClassDec.Vec2iVal.dot(v: TestClassDec.Vec2iVal): Int {
+   public fun pkg.TestClassDec.Vec2iVal.dot(v: pkg.TestClassDec.Vec2iVal): Int {
       return `$this$dot`.getX() * v.getX() + `$this$dot`.getY() * v.getY();// 11
    }
 
-   fun test() {
+   public fun test() {
       new TestClassDec.EmptyDec();
       var vec: TestClassDec.Vec2iVal = new TestClassDec.Vec2iVal(1, 2);// 16
       var vec1: TestClassDec.Vec2iVal = new TestClassDec.Vec2iVal(2, 4);// 17
@@ -16,28 +16,26 @@ class TestClassDec {
    class EmptyDec {
    }
 
-   class Vec2i {
-      fun Vec2i(x: Int, y: Int) {
-      }// 8
+   class Vec2i(x: Int, y: Int) {
    }
 
-   class Vec2iVal {
+   class Vec2iVal(x: Int, y: Int) {
       public final val x: Int
       public final val y: Int
 
-      fun Vec2iVal(x: Int, y: Int) {
+      init {
          this.x = x;// 7
          this.y = y;
       }
    }
 
-   class Vec2iVar {
+   class Vec2iVar(x: Int, y: Int) {
       public final var x: Int
          internal set
       public final var y: Int
          internal set
 
-      fun Vec2iVar(x: Int, y: Int) {
+      init {
          this.x = x;// 6
          this.y = y;
       }
@@ -105,48 +103,41 @@ class 'pkg/TestClassDec' {
    }
 }
 
-class 'pkg/TestClassDec$Vec2i' {
-   method '<init> (II)V' {
-      4      20
-   }
-}
-
 class 'pkg/TestClassDec$Vec2iVal' {
    method '<init> (II)V' {
-      4      28
-      5      28
-      6      28
-      7      28
-      8      28
-      9      29
-      a      29
-      b      29
-      c      29
-      d      29
-      e      30
+      4      26
+      5      26
+      6      26
+      7      26
+      8      26
+      9      27
+      a      27
+      b      27
+      c      27
+      d      27
+      e      28
    }
 }
 
 class 'pkg/TestClassDec$Vec2iVar' {
    method '<init> (II)V' {
-      4      40
-      5      40
-      6      40
-      7      40
-      8      40
-      9      41
-      a      41
-      b      41
-      c      41
-      d      41
-      e      42
+      4      38
+      5      38
+      6      38
+      7      38
+      8      38
+      9      39
+      a      39
+      b      39
+      c      39
+      d      39
+      e      40
    }
 }
 
 Lines mapping:
-6 <-> 41
-7 <-> 29
-8 <-> 21
+6 <-> 39
+7 <-> 27
 11 <-> 5
 16 <-> 10
 17 <-> 11
diff --git a/plugins/kotlin/testData/results/pkg/TestComparison.dec b/plugins/kotlin/testData/results/pkg/TestComparison.dec
index 0d336a916b..deae0a7218 100644
--- a/plugins/kotlin/testData/results/pkg/TestComparison.dec
+++ b/plugins/kotlin/testData/results/pkg/TestComparison.dec
@@ -1,27 +1,27 @@
 package pkg
 
 class TestComparison {
-   fun test2(a: Any, b: Any): Boolean {
+   public fun test2(a: Any, b: Any): Boolean {
       return a == b;// 5
    }
 
-   fun test3(a: Any, b: Any): Boolean {
+   public fun test3(a: Any, b: Any): Boolean {
       return a === b;// 9
    }
 
-   fun testNull2(a: Any?): Boolean {
+   public fun testNull2(a: Any?): Boolean {
       return a == null;// 13
    }
 
-   fun testNull3(a: Any?): Boolean {
+   public fun testNull3(a: Any?): Boolean {
       return a == null;// 17
    }
 
-   fun testNullDouble2(a: Any?, b: Any?): Boolean {
+   public fun testNullDouble2(a: Any?, b: Any?): Boolean {
       return a == b;// 21
    }
 
-   fun testNullDouble3(a: Any?, b: Any?): Boolean {
+   public fun testNullDouble3(a: Any?, b: Any?): Boolean {
       return a === b;// 25
    }
 }
diff --git a/plugins/kotlin/testData/results/pkg/TestCompileTimeErrors.dec b/plugins/kotlin/testData/results/pkg/TestCompileTimeErrors.dec
index fb9a7c5902..b39d3dee40 100644
--- a/plugins/kotlin/testData/results/pkg/TestCompileTimeErrors.dec
+++ b/plugins/kotlin/testData/results/pkg/TestCompileTimeErrors.dec
@@ -3,11 +3,11 @@ package pkg
 import org.jetbrains.annotations.Nullable
 
 class TestCompileTimeErrors {
-   fun <I, O extends I & TestCompileTimeErrors.Test> test(i: I): O {
+   public fun <I, O> test(i: I): O where O : I, O : pkg.TestCompileTimeErrors.Test {
       throw new NotImplementedError(null, 1, null);// 10
    }
 
-   fun test2(i: Int?): TestCompileTimeErrors.Test? {
+   public fun test2(i: Int?): pkg.TestCompileTimeErrors.Test? {
       return if (i == null) null else new TestCompileTimeErrors.Test(i) {
          @Nullable
          private final Integer testValue;
diff --git a/plugins/kotlin/testData/results/pkg/TestConstructors.dec b/plugins/kotlin/testData/results/pkg/TestConstructors.dec
index 527d01a9d1..734acf7b17 100644
--- a/plugins/kotlin/testData/results/pkg/TestConstructors.dec
+++ b/plugins/kotlin/testData/results/pkg/TestConstructors.dec
@@ -1,30 +1,40 @@
 package pkg
 
-class TestConstructors {
-   fun TestConstructors() {
-   }// 3
-
-   fun TestConstructors(a: Int) {
-      this();// 4
+class TestConstructors private constructor() {
+   public constructor(a: Int) : this() {// 4
       System.out.println("a = " + a);// 5
    }// 6
 
-   fun TestConstructors(a: Int, b: Int) {
-      this(a);// 8
+   public constructor(a: Int, b: Int) : this(a) {// 8
       System.out.println("b = " + b);// 9
    }// 10
 }
 
 class 'pkg/TestConstructors' {
-   method '<init> ()V' {
+   method '<init> (I)V' {
+      1      3
+      2      3
+      3      3
       4      4
+      5      4
+      6      4
+      7      4
+      8      4
+      9      4
+      a      4
+      b      4
+      c      4
+      e      4
+      f      4
+      10      4
+      11      5
    }
 
-   method '<init> (I)V' {
+   method '<init> (II)V' {
       1      7
       2      7
       3      7
-      4      8
+      4      7
       5      8
       6      8
       7      8
@@ -33,38 +43,18 @@ class 'pkg/TestConstructors' {
       a      8
       b      8
       c      8
-      e      8
+      d      8
       f      8
       10      8
-      11      9
-   }
-
-   method '<init> (II)V' {
-      1      12
-      2      12
-      3      12
-      4      12
-      5      13
-      6      13
-      7      13
-      8      13
-      9      13
-      a      13
-      b      13
-      c      13
-      d      13
-      f      13
-      10      13
-      11      13
-      12      14
+      11      8
+      12      9
    }
 }
 
 Lines mapping:
-3 <-> 5
-4 <-> 8
-5 <-> 9
-6 <-> 10
-8 <-> 13
-9 <-> 14
-10 <-> 15
+4 <-> 4
+5 <-> 5
+6 <-> 6
+8 <-> 8
+9 <-> 9
+10 <-> 10
diff --git a/plugins/kotlin/testData/results/pkg/TestContracts.dec b/plugins/kotlin/testData/results/pkg/TestContracts.dec
new file mode 100644
index 0000000000..26f6a6f008
--- /dev/null
+++ b/plugins/kotlin/testData/results/pkg/TestContracts.dec
@@ -0,0 +1,233 @@
+package pkg
+
+import java.util.Iterator
+import kotlin.contracts.InvocationKind
+
+class TestContracts {
+   public fun testSimpleContract(x: Int?): Int {
+      contract {
+         returns() implies (x != null)
+      }
+
+      if (x == null) {// 13
+         throw new IllegalStateException("x is null".toString());
+      } else {
+         return x;// 14
+      }
+   }
+
+   public fun testBooleanContract(a: Boolean, b: Boolean): Boolean? {
+      contract {
+         returns(true) implies (!a && !b)
+         returns(null) implies (a && b)
+         returns(false) implies ((a && !b || (!a && b)
+      }
+
+      return if (a && b) null else a || b;// 24
+   }
+
+   public fun testTypeContract(x: Any?): Int {
+      contract {
+         returns() implies (x is Int)
+      }
+
+      if (x !is Integer) {// 31
+         throw new IllegalStateException("x is not Int".toString());
+      } else {
+         return (x as java.lang.Number).intValue();// 32
+      }
+   }
+
+   public fun testFunctionalContract(f: () -> Int): Int {
+      contract {
+         callsInPlace(f, InvocationKind.EXACTLY_ONCE)
+      }
+
+      return (f.invoke() as java.lang.Number).intValue();// 39
+   }
+
+   public fun testFunctionalContract2(f: () -> Int, b: Boolean): Int {
+      contract {
+         callsInPlace(f, InvocationKind.AT_MOST_ONCE)
+      }
+
+      return if (b) (f.invoke() as java.lang.Number).intValue() else 0;// 46
+   }
+
+   public fun testFunctionalContract3(f: () -> Int, i: Int): Int {
+      contract {
+         callsInPlace(f)
+      }
+
+      var var3: java.lang.Iterable = (new IntRange(0, i)) as java.lang.Iterable;
+      var var4: Int = 0;
+      var var5: Iterator = var3.iterator();
+
+      while (var5.hasNext()) {
+         var var6: Int = (var5 as IntIterator).nextInt();
+         var4 += (f.invoke() as java.lang.Number).intValue();
+      }
+
+      return var4;// 53
+   }
+}
+
+class 'pkg/TestContracts' {
+   method 'testSimpleContract (Ljava/lang/Integer;)I' {
+      1      11
+      2      11
+      9      12
+      a      12
+      b      12
+      c      12
+      d      12
+      11      12
+      12      14
+      13      14
+      14      14
+      15      14
+      16      14
+   }
+
+   method 'testBooleanContract (ZZ)Ljava/lang/Boolean;' {
+      1      25
+      2      25
+      5      25
+      6      25
+      9      25
+      d      25
+      e      25
+      11      25
+      12      25
+      1a      25
+      1d      25
+   }
+
+   method 'testTypeContract (Ljava/lang/Object;)I' {
+      1      33
+      5      33
+      c      34
+      d      34
+      e      34
+      f      34
+      10      34
+      14      34
+      15      36
+      16      36
+      17      36
+      18      36
+      19      36
+      1a      36
+      1b      36
+      1c      36
+   }
+
+   method 'testFunctionalContract (Lkotlin/jvm/functions/Function0;)I' {
+      7      45
+      8      45
+      9      45
+      a      45
+      b      45
+      c      45
+      d      45
+      e      45
+      f      45
+      10      45
+      11      45
+      12      45
+      13      45
+   }
+
+   method 'testFunctionalContract2 (Lkotlin/jvm/functions/Function0;Z)I' {
+      7      53
+      8      53
+      b      53
+      c      53
+      d      53
+      e      53
+      f      53
+      10      53
+      11      53
+      12      53
+      13      53
+      14      53
+      15      53
+      16      53
+      1a      53
+      1b      53
+   }
+
+   method 'testFunctionalContract3 (Lkotlin/jvm/functions/Function0;I)I' {
+      b      61
+      c      61
+      10      61
+      11      61
+      12      61
+      13      61
+      14      62
+      15      62
+      16      62
+      17      63
+      18      63
+      19      63
+      1a      63
+      1b      63
+      1c      63
+      1d      63
+      1e      63
+      1f      65
+      20      65
+      21      65
+      22      65
+      23      65
+      24      65
+      25      65
+      29      66
+      2a      66
+      2b      66
+      2c      66
+      2d      66
+      2e      66
+      2f      66
+      30      66
+      31      66
+      32      66
+      3e      67
+      3f      67
+      40      67
+      41      67
+      42      67
+      43      67
+      44      67
+      45      67
+      46      67
+      47      67
+      48      67
+      49      67
+      4e      67
+      4f      67
+      51      67
+      52      67
+      56      70
+      57      70
+      58      70
+   }
+}
+
+Lines mapping:
+13 <-> 12
+14 <-> 15
+24 <-> 26
+31 <-> 34
+32 <-> 37
+39 <-> 46
+46 <-> 54
+53 <-> 71
+Not mapped:
+10
+18
+28
+36
+43
+50
+57
diff --git a/plugins/kotlin/testData/results/pkg/TestConvertedK2JOps.dec b/plugins/kotlin/testData/results/pkg/TestConvertedK2JOps.dec
index 323be91852..8e0855be92 100644
--- a/plugins/kotlin/testData/results/pkg/TestConvertedK2JOps.dec
+++ b/plugins/kotlin/testData/results/pkg/TestConvertedK2JOps.dec
@@ -1,36 +1,33 @@
 package pkg
 
-import java.util.List
-import java.util.Map
-import java.util.Set
-
 class TestConvertedK2JOps {
    public final val any: Any = new Object()
-   public final val list: List<String> = CollectionsKt.listOf(new String[]{"a", "b", "c"})
+   public final val list: List<String> = CollectionsKt.listOf(new java.lang.String[]{"a", "b", "c"})
    public final val map: Map<String, String> = MapsKt.mapOf(new Pair[]{TuplesKt.to("a", "b"), TuplesKt.to("c", "d")})
-   public final val set: Set<String> = SetsKt.setOf(new String[]{"a", "b", "c"})
+   public final val set: Set<String> = SetsKt.setOf(new java.lang.String[]{"a", "b", "c"})
+
 
-   fun codeConstructs() {
+   public fun codeConstructs() {
       System.out.println("Hello, world!");// 10
    }// 12
 }
 
 class 'pkg/TestConvertedK2JOps' {
    method 'codeConstructs ()V' {
-      0      13
-      1      13
-      2      13
-      3      13
-      4      13
-      6      13
-      7      13
-      8      13
-      c      14
+      0      10
+      1      10
+      2      10
+      3      10
+      4      10
+      6      10
+      7      10
+      8      10
+      c      11
    }
 }
 
 Lines mapping:
-10 <-> 14
-12 <-> 15
+10 <-> 11
+12 <-> 12
 Not mapped:
 11
diff --git a/plugins/kotlin/testData/results/pkg/TestDataClass.dec b/plugins/kotlin/testData/results/pkg/TestDataClass.dec
index 54ef427ddd..29e6c123f9 100644
--- a/plugins/kotlin/testData/results/pkg/TestDataClass.dec
+++ b/plugins/kotlin/testData/results/pkg/TestDataClass.dec
@@ -1,43 +1,41 @@
 package pkg
 
-import java.util.List
-
-data class TestDataClass {
+data class TestDataClass(dataClassVal: Regex, variableWithVeryLongName: Int, requestLineWrapsIfTheParamListIsTooLong: List<String>, nullability: String?) {
    public final val dataClassVal: Regex
    public final val nullability: String?
    public final val requestLineWrapsIfTheParamListIsTooLong: List<String>
    public final val variableWithVeryLongName: Int
 
-   fun TestDataClass(dataClassVal: Regex, variableWithVeryLongName: Int, requestLineWrapsIfTheParamListIsTooLong: MutableList<String>, nullability: String?) {
+   init {
       this.dataClassVal = dataClassVal;// 4
       this.variableWithVeryLongName = variableWithVeryLongName;// 5
       this.requestLineWrapsIfTheParamListIsTooLong = requestLineWrapsIfTheParamListIsTooLong;// 6
       this.nullability = nullability;// 7
    }// 3
 
-   fun component1(): Regex {
+   public operator fun component1(): Regex {
       return this.dataClassVal;
    }
 
-   fun component2(): Int {
+   public operator fun component2(): Int {
       return this.variableWithVeryLongName;
    }
 
-   fun component3(): MutableList<String> {
+   public operator fun component3(): List<String> {
       return this.requestLineWrapsIfTheParamListIsTooLong;
    }
 
-   fun component4(): String? {
+   public operator fun component4(): String? {
       return this.nullability;
    }
 
-   fun copy(dataClassVal: Regex, variableWithVeryLongName: Int, requestLineWrapsIfTheParamListIsTooLong: MutableList<String>, nullability: String?): TestDataClass {
+   public fun copy(dataClassVal: Regex, variableWithVeryLongName: Int, requestLineWrapsIfTheParamListIsTooLong: List<String>, nullability: String?): TestDataClass {
       return new TestDataClass(dataClassVal, variableWithVeryLongName, requestLineWrapsIfTheParamListIsTooLong, nullability);
    }
 
    @JvmStatic
    @JvmSynthetic
-   fun `copy$default`(var0: TestDataClass, var1: Regex, var2: Int, var3: List, var4: String, var5: Int, var6: Any): TestDataClass {
+   fun `copy$default`(var0: TestDataClass, var1: Regex, var2: Int, var3: java.util.List, var4: java.lang.String, var5: Int, var6: Any): TestDataClass {
       if ((var5 and 1) != 0) {
          var1 = var0.dataClassVal;
       }
@@ -57,7 +55,7 @@ data class TestDataClass {
       return var0.copy(var1, var2, var3, var4);
    }
 
-   fun toString(): String {
+   public open fun toString(): String {
       return "TestDataClass(dataClassVal="
          + this.dataClassVal
          + ", variableWithVeryLongName="
@@ -69,7 +67,7 @@ data class TestDataClass {
          + ")";
    }
 
-   fun hashCode(): Int {
+   public open fun hashCode(): Int {
       return (
                (this.dataClassVal.hashCode() * 31 + Integer.hashCode(this.variableWithVeryLongName)) * 31
                   + this.requestLineWrapsIfTheParamListIsTooLong.hashCode()
@@ -78,7 +76,7 @@ data class TestDataClass {
          + (if (this.nullability == null) 0 else this.nullability.hashCode());
    }
 
-   fun equals(other: Any?): Boolean {
+   public open operator fun equals(other: Any?): Boolean {
       if (this === other) {
          return true;
       } else if (other !is TestDataClass) {
@@ -100,265 +98,265 @@ data class TestDataClass {
 
 class 'pkg/TestDataClass' {
    method '<init> (Lkotlin/text/Regex;ILjava/util/List;Ljava/lang/String;)V' {
-      10      11
-      11      11
-      12      11
-      13      11
-      14      11
-      15      12
-      16      12
-      17      12
-      18      12
-      19      12
-      1a      13
-      1b      13
-      1c      13
-      1d      13
-      1e      13
-      1f      14
-      20      14
-      21      14
-      22      14
-      23      14
-      24      14
-      25      15
+      10      9
+      11      9
+      12      9
+      13      9
+      14      9
+      15      10
+      16      10
+      17      10
+      18      10
+      19      10
+      1a      11
+      1b      11
+      1c      11
+      1d      11
+      1e      11
+      1f      12
+      20      12
+      21      12
+      22      12
+      23      12
+      24      12
+      25      13
    }
 
    method 'component1 ()Lkotlin/text/Regex;' {
-      0      18
-      1      18
-      2      18
-      3      18
-      4      18
+      0      16
+      1      16
+      2      16
+      3      16
+      4      16
    }
 
    method 'component2 ()I' {
-      0      22
-      1      22
-      2      22
-      3      22
-      4      22
+      0      20
+      1      20
+      2      20
+      3      20
+      4      20
    }
 
    method 'component3 ()Ljava/util/List;' {
-      0      26
-      1      26
-      2      26
-      3      26
-      4      26
+      0      24
+      1      24
+      2      24
+      3      24
+      4      24
    }
 
    method 'component4 ()Ljava/lang/String;' {
-      0      30
-      1      30
-      2      30
-      3      30
-      4      30
+      0      28
+      1      28
+      2      28
+      3      28
+      4      28
    }
 
    method 'copy (Lkotlin/text/Regex;ILjava/util/List;Ljava/lang/String;)Lpkg/TestDataClass;' {
-      10      34
-      11      34
-      12      34
-      13      34
-      14      34
-      18      34
+      10      32
+      11      32
+      12      32
+      13      32
+      14      32
+      18      32
    }
 
    method 'copy$default (Lpkg/TestDataClass;Lkotlin/text/Regex;ILjava/util/List;Ljava/lang/String;ILjava/lang/Object;)Lpkg/TestDataClass;' {
-      0      40
-      1      40
-      2      40
-      3      40
-      4      40
-      7      41
-      8      41
-      9      41
-      a      41
-      b      41
-      c      44
-      d      44
-      e      44
-      f      44
-      10      44
-      13      45
-      14      45
-      15      45
-      16      45
-      17      45
-      18      48
-      19      48
-      1a      48
-      1b      48
-      1c      48
-      1f      49
-      20      49
-      21      49
-      22      49
-      23      49
-      24      52
-      25      52
-      26      52
-      27      52
-      28      52
-      29      52
-      2c      53
-      2d      53
-      2e      53
-      2f      53
-      30      53
-      31      53
-      32      56
-      33      56
-      34      56
-      35      56
-      36      56
-      37      56
-      38      56
-      39      56
-      3a      56
-      3b      56
+      0      38
+      1      38
+      2      38
+      3      38
+      4      38
+      7      39
+      8      39
+      9      39
+      a      39
+      b      39
+      c      42
+      d      42
+      e      42
+      f      42
+      10      42
+      13      43
+      14      43
+      15      43
+      16      43
+      17      43
+      18      46
+      19      46
+      1a      46
+      1b      46
+      1c      46
+      1f      47
+      20      47
+      21      47
+      22      47
+      23      47
+      24      50
+      25      50
+      26      50
+      27      50
+      28      50
+      29      50
+      2c      51
+      2d      51
+      2e      51
+      2f      51
+      30      51
+      31      51
+      32      54
+      33      54
+      34      54
+      35      54
+      36      54
+      37      54
+      38      54
+      39      54
+      3a      54
+      3b      54
    }
 
    method 'toString ()Ljava/lang/String;' {
-      0      61
-      1      61
-      2      61
-      3      61
-      4      63
-      5      63
-      6      63
-      7      63
-      8      65
-      9      65
-      a      65
-      b      65
-      c      67
-      d      67
-      e      67
-      f      67
-      10      60
-      11      60
-      12      60
-      13      60
-      14      60
-      15      60
+      0      59
+      1      59
+      2      59
+      3      59
+      4      61
+      5      61
+      6      61
+      7      61
+      8      63
+      9      63
+      a      63
+      b      63
+      c      65
+      d      65
+      e      65
+      f      65
+      10      58
+      11      58
+      12      58
+      13      58
+      14      58
+      15      58
    }
 
    method 'hashCode ()I' {
-      0      73
-      1      73
-      2      73
-      3      73
-      4      73
-      5      73
-      6      73
-      8      73
-      9      73
-      a      73
-      b      73
-      c      73
-      d      73
-      e      73
-      f      73
-      10      73
-      11      73
-      12      73
-      13      73
-      15      73
-      16      73
-      17      73
-      18      73
-      19      74
-      1a      74
-      1b      74
-      1c      74
-      1d      74
-      1e      74
-      1f      74
-      20      73
-      22      73
-      23      76
-      24      76
-      25      72
-      26      77
-      27      77
-      28      77
-      29      77
-      2a      77
-      2d      77
-      31      77
-      32      77
-      33      77
-      34      77
-      35      77
-      38      72
-      3b      72
+      0      71
+      1      71
+      2      71
+      3      71
+      4      71
+      5      71
+      6      71
+      8      71
+      9      71
+      a      71
+      b      71
+      c      71
+      d      71
+      e      71
+      f      71
+      10      71
+      11      71
+      12      71
+      13      71
+      15      71
+      16      71
+      17      71
+      18      71
+      19      72
+      1a      72
+      1b      72
+      1c      72
+      1d      72
+      1e      72
+      1f      72
+      20      71
+      22      71
+      23      74
+      24      74
+      25      70
+      26      75
+      27      75
+      28      75
+      29      75
+      2a      75
+      2d      75
+      31      75
+      32      75
+      33      75
+      34      75
+      35      75
+      38      70
+      3b      70
    }
 
    method 'equals (Ljava/lang/Object;)Z' {
-      0      81
-      1      81
-      2      81
-      5      82
-      6      82
-      7      83
-      b      83
-      e      84
-      f      84
-      10      86
-      11      86
-      12      86
-      13      86
-      14      86
-      15      87
-      16      87
-      17      87
-      18      87
-      19      87
-      1a      87
-      1b      87
-      1c      87
-      20      87
-      23      88
-      24      88
-      25      89
-      26      89
-      27      89
-      28      89
-      29      89
-      2a      89
-      2b      89
-      2c      89
-      2d      89
-      30      90
-      31      90
-      32      91
-      33      91
-      34      91
-      35      91
-      36      91
-      37      91
-      38      91
-      39      91
-      3d      91
-      40      92
-      41      92
-      42      94
-      43      94
-      44      94
-      45      94
-      46      94
-      47      94
-      48      94
-      49      94
-      4d      94
+      0      79
+      1      79
+      2      79
+      5      80
+      6      80
+      7      81
+      b      81
+      e      82
+      f      82
+      10      84
+      11      84
+      12      84
+      13      84
+      14      84
+      15      85
+      16      85
+      17      85
+      18      85
+      19      85
+      1a      85
+      1b      85
+      1c      85
+      20      85
+      23      86
+      24      86
+      25      87
+      26      87
+      27      87
+      28      87
+      29      87
+      2a      87
+      2b      87
+      2c      87
+      2d      87
+      30      88
+      31      88
+      32      89
+      33      89
+      34      89
+      35      89
+      36      89
+      37      89
+      38      89
+      39      89
+      3d      89
+      40      90
+      41      90
+      42      92
+      43      92
+      44      92
+      45      92
+      46      92
+      47      92
+      48      92
+      49      92
+      4d      92
    }
 }
 
 Lines mapping:
-3 <-> 16
-4 <-> 12
-5 <-> 13
-6 <-> 14
-7 <-> 15
+3 <-> 14
+4 <-> 10
+5 <-> 11
+6 <-> 12
+7 <-> 13
diff --git a/plugins/kotlin/testData/results/pkg/TestDestructors.dec b/plugins/kotlin/testData/results/pkg/TestDestructors.dec
index d94952f45d..cf9eb96cff 100644
--- a/plugins/kotlin/testData/results/pkg/TestDestructors.dec
+++ b/plugins/kotlin/testData/results/pkg/TestDestructors.dec
@@ -1,52 +1,51 @@
 package pkg
 
-import java.util.List
 import kotlin.jvm.functions.Function0
 
 class TestDestructors {
-   fun destructDataClasses(x: Pair<String, Integer>, y: Triple<? extends Number, Boolean, String>) {
-      System.out.println(x.component1() as String + " " + x.component2() as Integer);// 8 9
-      System.out.println(y.component1() as Number + " " + y.component2() as Boolean + " " + y.component3() as String);// 11 12
+   public fun destructDataClasses(x: Pair<String, Int?>, y: Triple<Number, Boolean?, String>) {
+      System.out.println(x.component1() as java.lang.String + " " + x.component2() as Integer);// 8 9
+      System.out.println(y.component1() as java.lang.Number + " " + y.component2() as java.lang.Boolean + " " + y.component3() as java.lang.String);// 11 12
    }// 13
 
-   fun destructDataClassesSpecial(x: Pair<Integer, String>, y: Triple) {
-      System.out.println((x.component1() as Number).intValue() + " " + x.component2() as String);// 19 20
-      var c: List = y.component1() as List;// 22
+   public fun destructDataClassesSpecial(x: Pair<Int, String>, y: Triple<List<Int>, Nothing?, Unit>) {
+      System.out.println((x.component1() as java.lang.Number).intValue() + " " + x.component2() as java.lang.String);// 19 20
+      var c: java.util.List = y.component1() as java.util.List;// 22
       var d: Void = y.component2() as Void;
       y.component3();
       System.out.println(c + " " + d + " " + Unit.INSTANCE);// 23
    }// 24
 
-   fun destructDataClassesSkip(x: Triple<String, Integer, String>, y: Triple<? extends Number, Boolean, String>) {
+   public fun destructDataClassesSkip(x: Triple<String, Int?, String>, y: Triple<Number, Boolean?, String>) {
       System.out.println(x.component2() as Integer);// 30 31
-      System.out.println(y.component1() as Number + " " + y.component3() as String);// 33 34
+      System.out.println(y.component1() as java.lang.Number + " " + y.component3() as java.lang.String);// 33 34
    }// 35
 
-   fun destructorImpossible(x: Pair): String {
-      var a: String = x.component1() as String;// 38
+   public fun destructorImpossible(x: Pair<String, Nothing>): String {
+      var a: java.lang.String = x.component1() as java.lang.String;// 38
       x.component2();
       throw new KotlinNothingValueException();
    }
 
-   fun destructExtensionFunction(x: Int) {
+   public fun destructExtensionFunction(x: Int) {
       System.out.println("" + this.component1(x) + this.component2(x) + this.component3(x));// 44 45
    }// 46
 
-   fun destructInlineLambda(x: () -> Int) {
+   public inline fun destructInlineLambda(x: () -> Int) {
       System.out
          .println(
             ""
-               + this.component1((x.invoke() as Number).intValue())// 49 50 85
-               + this.component2((x.invoke() as Number).intValue())// 86
-               + this.component3((x.invoke() as Number).intValue())// 87
+               + this.component1((x.invoke() as java.lang.Number).intValue())// 49 50 85
+               + this.component2((x.invoke() as java.lang.Number).intValue())// 86
+               + this.component3((x.invoke() as java.lang.Number).intValue())// 87
          );
    }// 51
 
-   fun callDestructInlineLambda() {
+   public fun callDestructInlineLambda() {
       System.out.println("" + this.component1(123) + this.component2(123) + this.component3(123));// 54 88 89 90 91 92
    }// 55
 
-   fun callDestructInlineLambdaWithControlFlow(x: Int) {
+   public fun callDestructInlineLambdaWithControlFlow(x: Int) {
       if (100 <= x && x < 1000) {
          var `a$iv`: Int = this.component1(x);// 95
          if (100 <= x && x < 1000) {// 96
@@ -58,852 +57,852 @@ class TestDestructors {
       }
    }// 99
 
-   fun destructInlineLambdaNoInline(x: () -> Int) {
+   public fun destructInlineLambdaNoInline(x: () -> Int) {
       System.out
          .println(
             ""
-               + this.component1((x.invoke() as Number).intValue())// 62 63 100
-               + this.component2((x.invoke() as Number).intValue())// 101
-               + this.component3((x.invoke() as Number).intValue())// 102
+               + this.component1((x.invoke() as java.lang.Number).intValue())// 62 63 100
+               + this.component2((x.invoke() as java.lang.Number).intValue())// 101
+               + this.component3((x.invoke() as java.lang.Number).intValue())// 102
          );
    }// 64
 
-   fun destructLambdaInline(x: Int) {
+   public fun destructLambdaInline(x: Int) {
       var var2: Function0 = new <undefinedtype>(x);// 67
       System.out
          .println(
             ""
-               + this.component1((var2.invoke() as Number).intValue())// 68 103
-               + this.component2((var2.invoke() as Number).intValue())// 104
-               + this.component3((var2.invoke() as Number).intValue())// 105
+               + this.component1((var2.invoke() as java.lang.Number).intValue())// 68 103
+               + this.component2((var2.invoke() as java.lang.Number).intValue())// 104
+               + this.component3((var2.invoke() as java.lang.Number).intValue())// 105
          );
    }// 69
 
-   fun Int.component1(): Int {
-      return String.valueOf(`$this$component1`).charAt(0) - 48;// 77
+   public operator fun Int.component1(): Int {
+      return java.lang.String.valueOf(`$this$component1`).charAt(0) - 48;// 77
    }
 
-   fun Int.component2(): Int {
-      return String.valueOf(`$this$component2`).charAt(1) - 48;// 78
+   public operator fun Int.component2(): Int {
+      return java.lang.String.valueOf(`$this$component2`).charAt(1) - 48;// 78
    }
 
-   fun Int.component3(): Int {
-      return String.valueOf(`$this$component3`).charAt(2) - 48;// 79
+   public operator fun Int.component3(): Int {
+      return java.lang.String.valueOf(`$this$component3`).charAt(2) - 48;// 79
    }
 
-   fun (() -> Int).component1(): Int {
-      return this.component1((`$this$component1`.invoke() as Number).intValue());// 81
+   public inline operator fun (() -> Int).component1(): Int {
+      return this.component1((`$this$component1`.invoke() as java.lang.Number).intValue());// 81
    }
 
-   fun (() -> Int).component2(): Int {
-      return this.component2((`$this$component2`.invoke() as Number).intValue());// 82
+   public inline operator fun (() -> Int).component2(): Int {
+      return this.component2((`$this$component2`.invoke() as java.lang.Number).intValue());// 82
    }
 
-   fun (() -> Int).component3(): Int {
-      return this.component3((`$this$component3`.invoke() as Number).intValue());// 83
+   public inline operator fun (() -> Int).component3(): Int {
+      return this.component3((`$this$component3`.invoke() as java.lang.Number).intValue());// 83
    }
 }
 
 class 'pkg/TestDestructors' {
    method 'destructDataClasses (Lkotlin/Pair;Lkotlin/Triple;)V' {
-      c      7
-      d      7
-      e      7
-      f      7
-      10      7
-      11      7
-      12      7
-      14      7
-      15      7
-      16      7
-      17      7
-      18      7
-      19      7
-      1a      7
-      1d      7
-      1e      7
-      1f      7
-      20      7
-      21      7
-      22      7
-      23      7
-      24      7
-      25      7
-      26      7
-      27      7
-      29      7
-      2a      7
-      2b      7
-      2c      8
-      2d      8
-      2e      8
-      2f      8
-      30      8
-      31      8
-      32      8
-      35      8
-      36      8
-      37      8
-      38      8
-      39      8
-      3a      8
-      3b      8
-      3e      8
-      3f      8
-      40      8
-      41      8
-      42      8
-      43      8
-      44      8
-      47      8
-      48      8
-      49      8
-      4a      8
-      4b      8
-      4c      8
-      4d      8
-      4e      8
-      4f      8
-      50      8
-      51      8
-      52      8
-      53      8
-      54      8
-      56      8
-      57      8
-      58      8
-      59      9
+      c      6
+      d      6
+      e      6
+      f      6
+      10      6
+      11      6
+      12      6
+      14      6
+      15      6
+      16      6
+      17      6
+      18      6
+      19      6
+      1a      6
+      1d      6
+      1e      6
+      1f      6
+      20      6
+      21      6
+      22      6
+      23      6
+      24      6
+      25      6
+      26      6
+      27      6
+      29      6
+      2a      6
+      2b      6
+      2c      7
+      2d      7
+      2e      7
+      2f      7
+      30      7
+      31      7
+      32      7
+      35      7
+      36      7
+      37      7
+      38      7
+      39      7
+      3a      7
+      3b      7
+      3e      7
+      3f      7
+      40      7
+      41      7
+      42      7
+      43      7
+      44      7
+      47      7
+      48      7
+      49      7
+      4a      7
+      4b      7
+      4c      7
+      4d      7
+      4e      7
+      4f      7
+      50      7
+      51      7
+      52      7
+      53      7
+      54      7
+      56      7
+      57      7
+      58      7
+      59      8
    }
 
    method 'destructDataClassesSpecial (Lkotlin/Pair;Lkotlin/Triple;)V' {
-      c      12
-      d      12
-      e      12
-      f      12
-      10      12
-      11      12
-      12      12
-      13      12
-      14      12
-      15      12
-      17      12
-      18      12
-      19      12
-      1a      12
-      1b      12
-      1c      12
-      1d      12
-      20      12
-      21      12
-      22      12
-      23      12
-      24      12
-      25      12
-      26      12
-      27      12
-      28      12
-      29      12
-      2a      12
-      2c      12
-      2d      12
-      2e      12
-      2f      13
-      30      13
-      31      13
-      32      13
-      33      13
-      34      13
-      35      13
-      36      13
-      37      13
-      38      14
-      39      14
-      3a      14
-      3b      14
-      3c      14
-      3d      14
-      3e      14
-      3f      14
-      40      14
-      41      15
-      42      15
-      43      15
-      44      15
-      46      16
-      47      16
-      48      16
-      4b      16
-      4c      16
-      4d      16
-      4e      16
-      4f      16
-      50      16
-      51      16
-      52      16
-      53      16
-      54      16
-      55      16
-      56      16
-      57      16
-      58      16
-      5a      16
-      5b      16
-      5c      16
-      5d      17
+      c      11
+      d      11
+      e      11
+      f      11
+      10      11
+      11      11
+      12      11
+      13      11
+      14      11
+      15      11
+      17      11
+      18      11
+      19      11
+      1a      11
+      1b      11
+      1c      11
+      1d      11
+      20      11
+      21      11
+      22      11
+      23      11
+      24      11
+      25      11
+      26      11
+      27      11
+      28      11
+      29      11
+      2a      11
+      2c      11
+      2d      11
+      2e      11
+      2f      12
+      30      12
+      31      12
+      32      12
+      33      12
+      34      12
+      35      12
+      36      12
+      37      12
+      38      13
+      39      13
+      3a      13
+      3b      13
+      3c      13
+      3d      13
+      3e      13
+      3f      13
+      40      13
+      41      14
+      42      14
+      43      14
+      44      14
+      46      15
+      47      15
+      48      15
+      4b      15
+      4c      15
+      4d      15
+      4e      15
+      4f      15
+      50      15
+      51      15
+      52      15
+      53      15
+      54      15
+      55      15
+      56      15
+      57      15
+      58      15
+      5a      15
+      5b      15
+      5c      15
+      5d      16
    }
 
    method 'destructDataClassesSkip (Lkotlin/Triple;Lkotlin/Triple;)V' {
-      c      20
-      d      20
-      e      20
-      f      20
-      10      20
-      11      20
-      12      20
-      14      20
-      15      20
-      16      20
-      17      20
-      18      20
-      19      20
-      1a      20
-      1b      21
-      1c      21
-      1d      21
-      1e      21
-      1f      21
-      20      21
-      21      21
-      24      21
-      25      21
-      26      21
-      27      21
-      28      21
-      29      21
-      2a      21
-      2d      21
-      2e      21
-      2f      21
-      30      21
-      31      21
-      32      21
-      33      21
-      34      21
-      35      21
-      36      21
-      37      21
-      38      21
-      3a      21
-      3b      21
-      3c      21
-      3d      22
+      c      19
+      d      19
+      e      19
+      f      19
+      10      19
+      11      19
+      12      19
+      14      19
+      15      19
+      16      19
+      17      19
+      18      19
+      19      19
+      1a      19
+      1b      20
+      1c      20
+      1d      20
+      1e      20
+      1f      20
+      20      20
+      21      20
+      24      20
+      25      20
+      26      20
+      27      20
+      28      20
+      29      20
+      2a      20
+      2d      20
+      2e      20
+      2f      20
+      30      20
+      31      20
+      32      20
+      33      20
+      34      20
+      35      20
+      36      20
+      37      20
+      38      20
+      3a      20
+      3b      20
+      3c      20
+      3d      21
    }
 
    method 'destructorImpossible (Lkotlin/Pair;)Ljava/lang/String;' {
-      6      25
-      7      25
-      8      25
-      9      25
-      a      25
-      b      25
-      c      25
-      d      25
-      e      26
-      f      26
-      10      26
-      11      26
-      1a      27
+      6      24
+      7      24
+      8      24
+      9      24
+      a      24
+      b      24
+      c      24
+      d      24
+      e      25
+      f      25
+      10      25
+      11      25
+      1a      26
    }
 
    method 'destructExtensionFunction (I)V' {
-      0      31
-      1      31
-      2      31
-      3      31
-      4      31
-      6      31
-      7      31
-      8      31
-      9      31
-      a      31
-      c      31
-      d      31
-      e      31
-      f      31
-      10      31
-      13      31
-      14      31
-      15      31
-      16      31
-      17      31
-      18      31
-      19      31
-      1a      31
-      1b      31
-      1c      31
-      1d      31
-      1e      31
-      20      31
-      21      31
-      22      31
-      23      32
+      0      30
+      1      30
+      2      30
+      3      30
+      4      30
+      6      30
+      7      30
+      8      30
+      9      30
+      a      30
+      c      30
+      d      30
+      e      30
+      f      30
+      10      30
+      13      30
+      14      30
+      15      30
+      16      30
+      17      30
+      18      30
+      19      30
+      1a      30
+      1b      30
+      1c      30
+      1d      30
+      1e      30
+      20      30
+      21      30
+      22      30
+      23      31
    }
 
    method 'destructInlineLambda (Lkotlin/jvm/functions/Function0;)V' {
-      8      38
-      b      38
-      11      38
-      12      38
-      13      38
-      14      38
-      15      38
-      16      38
-      17      38
-      18      38
-      19      38
-      1a      38
-      1b      38
-      1c      38
-      1d      38
-      1e      38
-      1f      38
-      20      38
-      21      38
-      22      38
-      24      39
-      27      39
-      2d      39
-      2e      39
-      2f      39
-      30      39
-      31      39
-      32      39
-      33      39
-      34      39
-      35      39
-      36      39
-      37      39
-      38      39
-      39      39
-      3a      39
-      3b      39
-      3c      39
-      3d      39
-      3e      39
-      41      40
-      44      40
-      4a      40
-      4b      40
-      4c      40
-      4d      40
-      4e      40
-      4f      40
-      50      40
-      51      40
-      52      40
-      53      40
-      54      40
-      55      40
-      56      40
-      57      40
-      58      40
-      59      40
-      5a      40
-      5b      40
-      5e      38
-      5f      39
-      60      39
-      61      40
-      62      40
-      63      37
-      64      37
-      65      37
-      66      37
-      67      37
-      68      35
-      69      35
-      6a      35
-      6c      36
-      6d      36
-      6e      36
-      6f      42
+      8      37
+      b      37
+      11      37
+      12      37
+      13      37
+      14      37
+      15      37
+      16      37
+      17      37
+      18      37
+      19      37
+      1a      37
+      1b      37
+      1c      37
+      1d      37
+      1e      37
+      1f      37
+      20      37
+      21      37
+      22      37
+      24      38
+      27      38
+      2d      38
+      2e      38
+      2f      38
+      30      38
+      31      38
+      32      38
+      33      38
+      34      38
+      35      38
+      36      38
+      37      38
+      38      38
+      39      38
+      3a      38
+      3b      38
+      3c      38
+      3d      38
+      3e      38
+      41      39
+      44      39
+      4a      39
+      4b      39
+      4c      39
+      4d      39
+      4e      39
+      4f      39
+      50      39
+      51      39
+      52      39
+      53      39
+      54      39
+      55      39
+      56      39
+      57      39
+      58      39
+      59      39
+      5a      39
+      5b      39
+      5e      37
+      5f      38
+      60      38
+      61      39
+      62      39
+      63      36
+      64      36
+      65      36
+      66      36
+      67      36
+      68      34
+      69      34
+      6a      34
+      6c      35
+      6d      35
+      6e      35
+      6f      41
    }
 
    method 'callDestructInlineLambda ()V' {
-      0      45
-      4      45
-      9      45
-      f      45
-      10      45
-      13      45
-      14      45
-      15      45
-      16      45
-      17      45
-      18      45
-      19      45
-      1c      45
-      22      45
-      23      45
-      29      45
-      2a      45
-      2d      45
-      2e      45
-      2f      45
-      30      45
-      31      45
-      32      45
-      33      45
-      35      45
-      3b      45
-      3c      45
-      42      45
-      43      45
-      46      45
-      47      45
-      48      45
-      49      45
-      4a      45
-      4b      45
-      4c      45
-      4f      45
-      50      45
-      51      45
-      52      45
-      53      45
-      54      45
-      55      45
-      56      45
-      57      45
-      58      45
-      59      45
-      5a      45
-      5b      45
-      5d      45
-      5e      45
-      5f      45
-      61      46
+      0      44
+      4      44
+      9      44
+      f      44
+      10      44
+      13      44
+      14      44
+      15      44
+      16      44
+      17      44
+      18      44
+      19      44
+      1c      44
+      22      44
+      23      44
+      29      44
+      2a      44
+      2d      44
+      2e      44
+      2f      44
+      30      44
+      31      44
+      32      44
+      33      44
+      35      44
+      3b      44
+      3c      44
+      42      44
+      43      44
+      46      44
+      47      44
+      48      44
+      49      44
+      4a      44
+      4b      44
+      4c      44
+      4f      44
+      50      44
+      51      44
+      52      44
+      53      44
+      54      44
+      55      44
+      56      44
+      57      44
+      58      44
+      59      44
+      5a      44
+      5b      44
+      5d      44
+      5e      44
+      5f      44
+      61      45
    }
 
    method 'callDestructInlineLambdaWithControlFlow (I)V' {
-      0      50
-      4      50
-      a      50
-      b      50
-      11      49
-      12      49
-      13      49
-      14      49
-      17      49
-      18      49
-      19      49
-      1a      49
-      1b      49
-      27      49
-      2a      50
-      2e      58
-      2f      50
-      30      50
-      31      50
-      32      50
-      33      50
-      34      50
-      35      50
-      36      50
-      37      50
-      38      52
-      39      52
-      3e      52
-      3f      52
-      45      51
-      46      51
-      47      51
-      48      51
-      49      51
-      4d      51
-      4e      51
-      4f      51
-      50      51
-      51      51
-      5d      51
-      60      52
-      64      58
-      65      52
-      66      52
-      67      52
-      68      52
-      69      52
-      6a      52
-      6b      52
-      6c      52
-      6d      52
-      6e      54
-      6f      54
-      74      54
-      75      54
-      7b      53
-      7c      53
-      7d      53
-      7e      53
-      7f      53
-      83      53
-      84      53
-      85      53
-      86      53
-      87      53
-      93      53
-      96      54
-      9a      58
-      9b      54
-      9c      54
-      9d      54
-      9e      54
-      9f      54
-      a0      54
-      a4      54
-      a5      54
-      a6      54
-      a7      54
-      a8      54
-      a9      54
-      aa      54
-      ab      54
-      ac      54
-      ad      54
-      ae      54
-      af      54
-      b0      54
-      b4      54
-      b8      58
+      0      49
+      4      49
+      a      49
+      b      49
+      11      48
+      12      48
+      13      48
+      14      48
+      17      48
+      18      48
+      19      48
+      1a      48
+      1b      48
+      27      48
+      2a      49
+      2e      57
+      2f      49
+      30      49
+      31      49
+      32      49
+      33      49
+      34      49
+      35      49
+      36      49
+      37      49
+      38      51
+      39      51
+      3e      51
+      3f      51
+      45      50
+      46      50
+      47      50
+      48      50
+      49      50
+      4d      50
+      4e      50
+      4f      50
+      50      50
+      51      50
+      5d      50
+      60      51
+      64      57
+      65      51
+      66      51
+      67      51
+      68      51
+      69      51
+      6a      51
+      6b      51
+      6c      51
+      6d      51
+      6e      53
+      6f      53
+      74      53
+      75      53
+      7b      52
+      7c      52
+      7d      52
+      7e      52
+      7f      52
+      83      52
+      84      52
+      85      52
+      86      52
+      87      52
+      93      52
+      96      53
+      9a      57
+      9b      53
+      9c      53
+      9d      53
+      9e      53
+      9f      53
+      a0      53
+      a4      53
+      a5      53
+      a6      53
+      a7      53
+      a8      53
+      a9      53
+      aa      53
+      ab      53
+      ac      53
+      ad      53
+      ae      53
+      af      53
+      b0      53
+      b4      53
+      b8      57
    }
 
    method 'destructInlineLambdaNoInline (Lkotlin/jvm/functions/Function0;)V' {
-      6      64
-      8      64
-      e      64
-      f      64
-      10      64
-      11      64
-      12      64
-      13      64
-      14      64
-      15      64
-      16      64
-      17      64
-      18      64
-      19      64
-      1a      64
-      1b      64
-      1c      64
-      1d      64
-      1e      64
-      20      65
-      23      65
-      29      65
-      2a      65
-      2b      65
-      2c      65
-      2d      65
-      2e      65
-      2f      65
-      30      65
-      31      65
-      32      65
-      33      65
-      34      65
-      35      65
-      36      65
-      37      65
-      38      65
-      39      65
-      3a      65
-      3c      66
-      3f      66
-      45      66
-      46      66
-      47      66
-      48      66
-      49      66
-      4a      66
-      4b      66
-      4c      66
-      4d      66
-      4e      66
-      4f      66
-      50      66
-      51      66
-      52      66
-      53      66
-      54      66
-      55      66
-      56      66
-      59      64
-      5a      65
-      5b      66
-      5c      66
-      5d      63
-      5e      63
-      5f      63
-      60      63
-      61      63
-      62      61
-      63      61
-      64      61
-      66      62
-      67      62
-      68      62
-      69      68
+      6      63
+      8      63
+      e      63
+      f      63
+      10      63
+      11      63
+      12      63
+      13      63
+      14      63
+      15      63
+      16      63
+      17      63
+      18      63
+      19      63
+      1a      63
+      1b      63
+      1c      63
+      1d      63
+      1e      63
+      20      64
+      23      64
+      29      64
+      2a      64
+      2b      64
+      2c      64
+      2d      64
+      2e      64
+      2f      64
+      30      64
+      31      64
+      32      64
+      33      64
+      34      64
+      35      64
+      36      64
+      37      64
+      38      64
+      39      64
+      3a      64
+      3c      65
+      3f      65
+      45      65
+      46      65
+      47      65
+      48      65
+      49      65
+      4a      65
+      4b      65
+      4c      65
+      4d      65
+      4e      65
+      4f      65
+      50      65
+      51      65
+      52      65
+      53      65
+      54      65
+      55      65
+      56      65
+      59      63
+      5a      64
+      5b      65
+      5c      65
+      5d      62
+      5e      62
+      5f      62
+      60      62
+      61      62
+      62      60
+      63      60
+      64      60
+      66      61
+      67      61
+      68      61
+      69      67
    }
 
    method 'destructLambdaInline (I)V' {
-      4      71
-      8      71
-      9      71
-      a      71
-      b      71
-      c      75
-      f      75
-      15      75
-      16      75
-      17      75
-      18      75
-      19      75
-      1a      75
-      1b      75
-      1c      75
-      1d      75
-      1e      75
-      1f      75
-      20      75
-      21      75
-      22      75
-      23      75
-      24      75
-      25      75
-      26      75
-      28      76
-      2b      76
-      31      76
-      32      76
-      33      76
-      34      76
-      35      76
-      36      76
-      37      76
-      38      76
-      39      76
-      3a      76
-      3b      76
-      3c      76
-      3d      76
-      3e      76
-      3f      76
-      40      76
-      41      76
-      42      76
-      45      77
-      48      77
-      4e      77
-      4f      77
-      50      77
-      51      77
-      52      77
-      53      77
-      54      77
-      55      77
-      56      77
-      57      77
-      58      77
-      59      77
-      5a      77
-      5b      77
-      5c      77
-      5d      77
-      5e      77
-      5f      77
-      62      75
-      63      76
-      64      76
-      65      77
-      66      77
-      67      74
-      68      74
-      69      74
-      6a      74
-      6b      74
-      6c      72
-      6d      72
-      6e      72
-      70      73
-      71      73
-      72      73
-      73      79
+      4      70
+      8      70
+      9      70
+      a      70
+      b      70
+      c      74
+      f      74
+      15      74
+      16      74
+      17      74
+      18      74
+      19      74
+      1a      74
+      1b      74
+      1c      74
+      1d      74
+      1e      74
+      1f      74
+      20      74
+      21      74
+      22      74
+      23      74
+      24      74
+      25      74
+      26      74
+      28      75
+      2b      75
+      31      75
+      32      75
+      33      75
+      34      75
+      35      75
+      36      75
+      37      75
+      38      75
+      39      75
+      3a      75
+      3b      75
+      3c      75
+      3d      75
+      3e      75
+      3f      75
+      40      75
+      41      75
+      42      75
+      45      76
+      48      76
+      4e      76
+      4f      76
+      50      76
+      51      76
+      52      76
+      53      76
+      54      76
+      55      76
+      56      76
+      57      76
+      58      76
+      59      76
+      5a      76
+      5b      76
+      5c      76
+      5d      76
+      5e      76
+      5f      76
+      62      74
+      63      75
+      64      75
+      65      76
+      66      76
+      67      73
+      68      73
+      69      73
+      6a      73
+      6b      73
+      6c      71
+      6d      71
+      6e      71
+      70      72
+      71      72
+      72      72
+      73      78
    }
 
    method 'component1 (I)I' {
-      0      82
-      1      82
-      2      82
-      3      82
-      4      82
-      5      82
-      6      82
-      7      82
-      8      82
-      9      82
-      a      82
-      b      82
+      0      81
+      1      81
+      2      81
+      3      81
+      4      81
+      5      81
+      6      81
+      7      81
+      8      81
+      9      81
+      a      81
+      b      81
    }
 
    method 'component2 (I)I' {
-      0      86
-      1      86
-      2      86
-      3      86
-      4      86
-      5      86
-      6      86
-      7      86
-      8      86
-      9      86
-      a      86
-      b      86
+      0      85
+      1      85
+      2      85
+      3      85
+      4      85
+      5      85
+      6      85
+      7      85
+      8      85
+      9      85
+      a      85
+      b      85
    }
 
    method 'component3 (I)I' {
-      0      90
-      1      90
-      2      90
-      3      90
-      4      90
-      5      90
-      6      90
-      7      90
-      8      90
-      9      90
-      a      90
-      b      90
+      0      89
+      1      89
+      2      89
+      3      89
+      4      89
+      5      89
+      6      89
+      7      89
+      8      89
+      9      89
+      a      89
+      b      89
    }
 
    method 'component1 (Lkotlin/jvm/functions/Function0;)I' {
-      8      94
-      9      94
-      a      94
-      b      94
-      c      94
-      d      94
-      e      94
-      f      94
-      10      94
-      11      94
-      12      94
-      13      94
-      14      94
-      15      94
-      16      94
-      17      94
-      18      94
+      8      93
+      9      93
+      a      93
+      b      93
+      c      93
+      d      93
+      e      93
+      f      93
+      10      93
+      11      93
+      12      93
+      13      93
+      14      93
+      15      93
+      16      93
+      17      93
+      18      93
    }
 
    method 'component2 (Lkotlin/jvm/functions/Function0;)I' {
-      8      98
-      9      98
-      a      98
-      b      98
-      c      98
-      d      98
-      e      98
-      f      98
-      10      98
-      11      98
-      12      98
-      13      98
-      14      98
-      15      98
-      16      98
-      17      98
-      18      98
+      8      97
+      9      97
+      a      97
+      b      97
+      c      97
+      d      97
+      e      97
+      f      97
+      10      97
+      11      97
+      12      97
+      13      97
+      14      97
+      15      97
+      16      97
+      17      97
+      18      97
    }
 
    method 'component3 (Lkotlin/jvm/functions/Function0;)I' {
-      8      102
-      9      102
-      a      102
-      b      102
-      c      102
-      d      102
-      e      102
-      f      102
-      10      102
-      11      102
-      12      102
-      13      102
-      14      102
-      15      102
-      16      102
-      17      102
-      18      102
+      8      101
+      9      101
+      a      101
+      b      101
+      c      101
+      d      101
+      e      101
+      f      101
+      10      101
+      11      101
+      12      101
+      13      101
+      14      101
+      15      101
+      16      101
+      17      101
+      18      101
    }
 }
 
 Lines mapping:
-8 <-> 8
-9 <-> 8
-11 <-> 9
-12 <-> 9
-13 <-> 10
-19 <-> 13
-20 <-> 13
-22 <-> 14
-23 <-> 17
-24 <-> 18
-30 <-> 21
-31 <-> 21
-33 <-> 22
-34 <-> 22
-35 <-> 23
-38 <-> 26
-44 <-> 32
-45 <-> 32
-46 <-> 33
-49 <-> 39
-50 <-> 39
-51 <-> 43
-54 <-> 46
-55 <-> 47
-58 <-> 54
-62 <-> 65
-63 <-> 65
-64 <-> 69
-67 <-> 72
-68 <-> 76
-69 <-> 80
-77 <-> 83
-78 <-> 87
-79 <-> 91
-81 <-> 95
-82 <-> 99
-83 <-> 103
-85 <-> 39
-86 <-> 40
-87 <-> 41
-88 <-> 46
-89 <-> 46
-90 <-> 46
-91 <-> 46
-92 <-> 46
-94 <-> 55
-95 <-> 51
-96 <-> 52
-97 <-> 54
-98 <-> 55
-99 <-> 59
-100 <-> 65
-101 <-> 66
-102 <-> 67
-103 <-> 76
-104 <-> 77
-105 <-> 78
+8 <-> 7
+9 <-> 7
+11 <-> 8
+12 <-> 8
+13 <-> 9
+19 <-> 12
+20 <-> 12
+22 <-> 13
+23 <-> 16
+24 <-> 17
+30 <-> 20
+31 <-> 20
+33 <-> 21
+34 <-> 21
+35 <-> 22
+38 <-> 25
+44 <-> 31
+45 <-> 31
+46 <-> 32
+49 <-> 38
+50 <-> 38
+51 <-> 42
+54 <-> 45
+55 <-> 46
+58 <-> 53
+62 <-> 64
+63 <-> 64
+64 <-> 68
+67 <-> 71
+68 <-> 75
+69 <-> 79
+77 <-> 82
+78 <-> 86
+79 <-> 90
+81 <-> 94
+82 <-> 98
+83 <-> 102
+85 <-> 38
+86 <-> 39
+87 <-> 40
+88 <-> 45
+89 <-> 45
+90 <-> 45
+91 <-> 45
+92 <-> 45
+94 <-> 54
+95 <-> 50
+96 <-> 51
+97 <-> 53
+98 <-> 54
+99 <-> 58
+100 <-> 64
+101 <-> 65
+102 <-> 66
+103 <-> 75
+104 <-> 76
+105 <-> 77
 Not mapped:
 59
 93
diff --git a/plugins/kotlin/testData/results/pkg/TestExtensionFun.dec b/plugins/kotlin/testData/results/pkg/TestExtensionFun.dec
index 2ca0acb77f..1439805c84 100644
--- a/plugins/kotlin/testData/results/pkg/TestExtensionFun.dec
+++ b/plugins/kotlin/testData/results/pkg/TestExtensionFun.dec
@@ -1,12 +1,12 @@
 package pkg
 
 class TestExtensionFun {
-   fun CharSequence.repeat2(n: Int): String {
+   public fun CharSequence.repeat2(n: Int): String {
       return StringsKt.repeat(`$this$repeat2`, n);// 5
    }
 
-   fun test() {
-      System.out.println(this.repeat2("Bye " as CharSequence, 2));// 9
+   public fun test() {
+      System.out.println(this.repeat2("Bye " as java.lang.CharSequence, 2));// 9
    }// 10
 }
 
diff --git a/plugins/kotlin/testData/results/pkg/TestForRange.dec b/plugins/kotlin/testData/results/pkg/TestForRange.dec
index fcf3892904..c09d5857d9 100644
--- a/plugins/kotlin/testData/results/pkg/TestForRange.dec
+++ b/plugins/kotlin/testData/results/pkg/TestForRange.dec
@@ -3,19 +3,19 @@ package pkg
 import kotlin.internal.ProgressionUtilKt
 
 class TestForRange {
-   fun testInt() {
+   public fun testInt() {
       for (int i = 1; i < 11; i++) {// 5
          System.out.println(i);// 6
       }
    }// 8
 
-   fun testChar() {
+   public fun testChar() {
       for (char c = 'a'; c < '{'; c++) {// 11
          System.out.println(c);// 12
       }
    }// 14
 
-   fun testIntStep() {
+   public fun testIntStep() {
       var i: Int = 1;
       var var2: Int = ProgressionUtilKt.getProgressionLastElement(1, 10, 2);
       if (1 <= var2) {
@@ -30,7 +30,7 @@ class TestForRange {
       }
    }// 20
 
-   fun testIntStepX(x: Int) {
+   public fun testIntStepX(x: Int) {
       if (x <= 0) {
          throw new IllegalArgumentException("Step must be positive, was: " + x + ".");
       } else {
@@ -49,13 +49,13 @@ class TestForRange {
       }
    }// 26
 
-   fun testIntDownTo() {
+   public fun testIntDownTo() {
       for (int i = 10; 0 < i; i--) {// 29
          System.out.println(i);// 30
       }
    }// 32
 
-   fun testIntDownToStep() {
+   public fun testIntDownToStep() {
       var i: Int = 10;
       var var2: Int = ProgressionUtilKt.getProgressionLastElement(10, 1, -2);
       if (var2 <= 10) {
@@ -70,7 +70,7 @@ class TestForRange {
       }
    }// 38
 
-   fun testIntDownToStepX(x: Int) {
+   public fun testIntDownToStepX(x: Int) {
       if (x <= 0) {
          throw new IllegalArgumentException("Step must be positive, was: " + x + ".");
       } else {
@@ -90,13 +90,13 @@ class TestForRange {
       }
    }// 44
 
-   fun testUntil() {
+   public fun testUntil() {
       for (int i = 1; i < 10; i++) {// 47
          System.out.println(i);// 48
       }
    }// 50
 
-   fun testUntilStep() {
+   public fun testUntilStep() {
       var var1: IntProgression = RangesKt.step(RangesKt.until(1, 100) as IntProgression, 2);
       var i: Int = var1.getFirst();
       var var3: Int = var1.getLast();
@@ -113,7 +113,7 @@ class TestForRange {
       }
    }// 56
 
-   fun testUntilStepX(x: Int) {
+   public fun testUntilStepX(x: Int) {
       var var2: IntProgression = RangesKt.step(RangesKt.until(1, 100) as IntProgression, x);
       var i: Int = var2.getFirst();
       var var4: Int = var2.getLast();
@@ -130,7 +130,7 @@ class TestForRange {
       }
    }// 62
 
-   fun testIntY(x: Int, y: Int) {
+   public fun testIntY(x: Int, y: Int) {
       var i: Int = x;
       if (x <= y) {
          while (true) {
@@ -144,7 +144,7 @@ class TestForRange {
       }
    }// 68
 
-   fun testIntYStep(x: Int, y: Int) {
+   public fun testIntYStep(x: Int, y: Int) {
       var i: Int = x;
       var var4: Int = ProgressionUtilKt.getProgressionLastElement(x, y, 2);
       if (x <= var4) {
@@ -159,7 +159,7 @@ class TestForRange {
       }
    }// 74
 
-   fun testIntYStepX(x: Int, y: Int, z: Int) {
+   public fun testIntYStepX(x: Int, y: Int, z: Int) {
       if (z <= 0) {
          throw new IllegalArgumentException("Step must be positive, was: " + z + ".");
       } else {
diff --git a/plugins/kotlin/testData/results/pkg/TestFunVarargs.dec b/plugins/kotlin/testData/results/pkg/TestFunVarargs.dec
index 447babc1eb..84b88115fd 100644
--- a/plugins/kotlin/testData/results/pkg/TestFunVarargs.dec
+++ b/plugins/kotlin/testData/results/pkg/TestFunVarargs.dec
@@ -3,28 +3,28 @@ package pkg
 import java.util.Arrays
 
 class TestFunVarargs {
-   fun printAll(vararg messages: String) {
-      for (String m : messages) {// 5
+   public fun printAll(vararg messages: String) {
+      for (java.lang.String m : messages) {// 5
          System.out.println(m);
       }
    }// 6
 
-   fun printAllArray(messages: Array<String>) {
-      for (String m : messages) {// 9
+   public fun printAllArray(messages: Array<out String>) {
+      for (java.lang.String m : messages) {// 9
          System.out.println(m);
       }
    }// 10
 
-   fun log(vararg entries: String) {
-      this.printAll(Arrays.copyOf(entries, entries.length) as String[]);// 13
+   public fun log(vararg entries: String) {
+      this.printAll(Arrays.copyOf(entries, entries.length) as java.lang.String[]);// 13
       this.printAllArray(entries);// 14
    }// 15
 
-   fun test() {
+   public fun test() {
       this.log("a", "b", "c");// 18
    }// 19
 
-   fun nestedArrays(e0: Array<String>, e1: Array<Any>, e2: Array<Array<Array<String>>>) {
+   public fun nestedArrays(e0: Array<String>, e1: Array<in String>, e2: Array<Array<Array<String>>>) {
    }// 23
 }
 
diff --git a/plugins/kotlin/testData/results/pkg/TestFuncRef.dec b/plugins/kotlin/testData/results/pkg/TestFuncRef.dec
index bff6216931..b9060c2077 100644
--- a/plugins/kotlin/testData/results/pkg/TestFuncRef.dec
+++ b/plugins/kotlin/testData/results/pkg/TestFuncRef.dec
@@ -1,14 +1,14 @@
 package pkg
 
-fun accept(f: (Int?) -> String) {
+public fun accept(f: (Int) -> String) {
    System.out.println(f.invoke(5));
 }// 3
 
-fun function(r: Int): String {
-   return StringsKt.repeat("OK" as CharSequence, r);// 6
+public fun function(r: Int): String {
+   return StringsKt.repeat("OK" as java.lang.CharSequence, r);// 6
 }
 
-fun test() {
+public fun test() {
    accept(<unknownclass>.INSTANCE);// 10
 }// 11
 
diff --git a/plugins/kotlin/testData/results/pkg/TestGenerics.dec b/plugins/kotlin/testData/results/pkg/TestGenerics.dec
index 4b619f6881..7a8687b667 100644
--- a/plugins/kotlin/testData/results/pkg/TestGenerics.dec
+++ b/plugins/kotlin/testData/results/pkg/TestGenerics.dec
@@ -1,21 +1,21 @@
 package pkg
 
 class TestGenerics<T> {
-   fun <T> genericFun(v: T): T {
+   public fun <T> genericFun(v: T): T {
       return (T)v;// 5
    }
 
-   fun <T> nullableGeneric(v: T): T? {
+   public fun <T> nullableGeneric(v: T): T? {
       return null;// 9
    }
 
-   fun <T> subType(v: TestGenerics<? extends T>) {
+   public fun <T> subType(v: TestGenerics<out T>) {
    }// 13
 
-   fun <T> superType(v: TestGenerics<? super T>) {
+   public fun <T> superType(v: TestGenerics<in T>) {
    }// 16
 
-   fun any(v: TestGenerics<?>) {
+   public fun any(v: TestGenerics<*>) {
    }// 19
 }
 
diff --git a/plugins/kotlin/testData/results/pkg/TestIfRange.dec b/plugins/kotlin/testData/results/pkg/TestIfRange.dec
index fca0b8da14..b1b89609e5 100644
--- a/plugins/kotlin/testData/results/pkg/TestIfRange.dec
+++ b/plugins/kotlin/testData/results/pkg/TestIfRange.dec
@@ -1,73 +1,73 @@
 package pkg
 
 class TestIfRange {
-   fun testInt(x: Int) {
+   public fun testInt(x: Int) {
       if (1 <= x && x < 11) {// 5
          System.out.println(x);// 6
       }
    }// 8
 
-   fun testChar(x: Char) {
+   public fun testChar(x: Char) {
       if ('a' <= x && x < '{') {// 11
          System.out.println(x);// 12
       }
    }// 14
 
-   fun testInvertedInt(x: Int) {
+   public fun testInvertedInt(x: Int) {
       if (1 > x || x >= 11) {// 17
          System.out.println(x);// 18
       }
    }// 20
 
-   fun testIntStep(x: Int) {
-      if (CollectionsKt.contains(RangesKt.step((new IntRange(1, 100)) as IntProgression, 2) as Iterable, x)) {// 23
+   public fun testIntStep(x: Int) {
+      if (CollectionsKt.contains(RangesKt.step((new IntRange(1, 100)) as IntProgression, 2) as java.lang.Iterable, x)) {// 23
          System.out.println(x);// 24
       }
    }// 26
 
-   fun testIntStepY(x: Int, y: Int) {
-      if (CollectionsKt.contains(RangesKt.step((new IntRange(1, 100)) as IntProgression, y) as Iterable, x)) {// 28
+   public fun testIntStepY(x: Int, y: Int) {
+      if (CollectionsKt.contains(RangesKt.step((new IntRange(1, 100)) as IntProgression, y) as java.lang.Iterable, x)) {// 28
          System.out.println(x);// 29
       }
    }// 31
 
-   fun testIntY(x: Int, y: Int) {
+   public fun testIntY(x: Int, y: Int) {
       if (1 <= x && x <= y) {// 34
          System.out.println(x);// 35
       }
    }// 37
 
-   fun testIntDownTo(x: Int) {
-      if (CollectionsKt.contains(RangesKt.downTo(10, 1) as Iterable, x)) {// 40
+   public fun testIntDownTo(x: Int) {
+      if (CollectionsKt.contains(RangesKt.downTo(10, 1) as java.lang.Iterable, x)) {// 40
          System.out.println(x);// 41
       }
    }// 43
 
-   fun testIntDownToStep(x: Int) {
-      if (CollectionsKt.contains(RangesKt.step(RangesKt.downTo(10, 1), 2) as Iterable, x)) {// 46
+   public fun testIntDownToStep(x: Int) {
+      if (CollectionsKt.contains(RangesKt.step(RangesKt.downTo(10, 1), 2) as java.lang.Iterable, x)) {// 46
          System.out.println(x);// 47
       }
    }// 49
 
-   fun testIntUntil(x: Int) {
+   public fun testIntUntil(x: Int) {
       if (1 <= x && x < 10) {// 52
          System.out.println(x);// 53
       }
    }// 55
 
-   fun testIntUntilStep(x: Int) {
-      if (CollectionsKt.contains(RangesKt.step(RangesKt.until(1, 100) as IntProgression, 2) as Iterable, x)) {// 58
+   public fun testIntUntilStep(x: Int) {
+      if (CollectionsKt.contains(RangesKt.step(RangesKt.until(1, 100) as IntProgression, 2) as java.lang.Iterable, x)) {// 58
          System.out.println(x);// 59
       }
    }// 61
 
-   fun testIntUntilY(x: Int, y: Int) {
+   public fun testIntUntilY(x: Int, y: Int) {
       if (1 <= x && x < y) {// 64
          System.out.println(x);// 65
       }
    }// 67
 
-   fun testIntUntilSelf(x: Int) {
+   public fun testIntUntilSelf(x: Int) {
       if (1 <= x && x < x) {// 70
          System.out.println(x);// 71
       }
diff --git a/plugins/kotlin/testData/results/pkg/TestInfixFun.dec b/plugins/kotlin/testData/results/pkg/TestInfixFun.dec
index 2a3841903c..abfe471ee7 100644
--- a/plugins/kotlin/testData/results/pkg/TestInfixFun.dec
+++ b/plugins/kotlin/testData/results/pkg/TestInfixFun.dec
@@ -1,30 +1,30 @@
 package pkg
 
 class TestInfixFun {
-   fun test() {
+   public fun test() {
       System.out.println(test$times(2, "Bye "));// 7
    }// 8
 
-   fun Int.mult(str: String): String {
-      return StringsKt.repeat(str as CharSequence, `$this$mult`);// 10
+   public infix fun Int.mult(str: String): String {
+      return StringsKt.repeat(str as java.lang.CharSequence, `$this$mult`);// 10
    }
 
-   fun testOuter() {
+   public fun testOuter() {
       System.out.println(this.mult(2, "Bye "));// 14
    }// 15
 
-   fun testDuplicate() {
+   public fun testDuplicate() {
       System.out.println(testDuplicate$mult(2, "Bye "));// 20
    }// 21
 
    @JvmStatic
-   fun Int.`test$times`(str: String): String {
-      return StringsKt.repeat(str as CharSequence, `$this$test_u24times`);// 5
+   fun Int.`test$times`(str: java.lang.String): java.lang.String {
+      return StringsKt.repeat(str as java.lang.CharSequence, `$this$test_u24times`);// 5
    }
 
    @JvmStatic
-   fun Int.`testDuplicate$mult`(str: String): String {
-      return StringsKt.repeat(str as CharSequence, `$this$testDuplicate_u24mult` + 1);// 18
+   fun Int.`testDuplicate$mult`(str: java.lang.String): java.lang.String {
+      return StringsKt.repeat(str as java.lang.CharSequence, `$this$testDuplicate_u24mult` + 1);// 18
    }
 }
 
diff --git a/plugins/kotlin/testData/results/pkg/TestKotlinTypes.dec b/plugins/kotlin/testData/results/pkg/TestKotlinTypes.dec
index 6c8c0d080c..4f22fe26c0 100644
--- a/plugins/kotlin/testData/results/pkg/TestKotlinTypes.dec
+++ b/plugins/kotlin/testData/results/pkg/TestKotlinTypes.dec
@@ -5,16 +5,17 @@ import kotlin.jvm.functions.Function1
 class TestKotlinTypes {
    public final val consumer: (Int) -> Unit = <unknownclass>.INSTANCE as Function1
 
-   fun throwAlways(): Void {
+
+   public fun throwAlways(): Nothing {
       throw new Exception();// 5
    }
 }
 
 class 'pkg/TestKotlinTypes' {
    method 'throwAlways ()Ljava/lang/Void;' {
-      7      8
+      7      9
    }
 }
 
 Lines mapping:
-5 <-> 9
+5 <-> 10
diff --git a/plugins/kotlin/testData/results/pkg/TestKt.dec b/plugins/kotlin/testData/results/pkg/TestKt.dec
index 4004cf8360..df4e6f6630 100644
--- a/plugins/kotlin/testData/results/pkg/TestKt.dec
+++ b/plugins/kotlin/testData/results/pkg/TestKt.dec
@@ -1,7 +1,7 @@
 package pkg
 
 class TestKt {
-   fun test() {
+   public fun test() {
       System.out.println("Hello, world!");// 5
    }// 6
 }
diff --git a/plugins/kotlin/testData/results/pkg/TestLabeledJumps.dec b/plugins/kotlin/testData/results/pkg/TestLabeledJumps.dec
index 21a61d4bc9..b6d221b59c 100644
--- a/plugins/kotlin/testData/results/pkg/TestLabeledJumps.dec
+++ b/plugins/kotlin/testData/results/pkg/TestLabeledJumps.dec
@@ -1,11 +1,11 @@
 package pkg
 
 class TestLabeledJumps {
-   fun testContinue(tester: (Int?) -> Boolean) {
+   public fun testContinue(tester: (Int) -> Boolean) {
       label24:
       for (int i = 1; i < 101; i++) {// 5
          for (int j = 1; j < 101; j++) {// 6
-            if (tester.invoke(j) as Boolean) {// 7
+            if (tester.invoke(j) as java.lang.Boolean) {// 7
                continue label24;
             }
 
@@ -16,11 +16,11 @@ class TestLabeledJumps {
       }
    }// 16
 
-   fun testBreak(tester: (Int?) -> Boolean) {
+   public fun testBreak(tester: (Int) -> Boolean) {
       label22:
       for (int i = 1; i < 101; i++) {// 19
          for (int j = 1; j < 101; j++) {// 20
-            if (tester.invoke(j) as Boolean) {// 21
+            if (tester.invoke(j) as java.lang.Boolean) {// 21
                break label22;
             }
 
diff --git a/plugins/kotlin/testData/results/pkg/TestNonInlineLambda.dec b/plugins/kotlin/testData/results/pkg/TestNonInlineLambda.dec
index 3ffbe26cda..2cb91f1ab6 100644
--- a/plugins/kotlin/testData/results/pkg/TestNonInlineLambda.dec
+++ b/plugins/kotlin/testData/results/pkg/TestNonInlineLambda.dec
@@ -12,29 +12,30 @@ open class TestNonInlineLambda {
    public final var stringField: String = ""
       internal set
 
-   fun testCaptureInt(x: Int) {
+
+   public fun testCaptureInt(x: Int) {
       this.execute(new <undefinedtype>(x));// 7 8
    }// 11
 
-   fun testCaptureObject(x: String) {
+   public fun testCaptureObject(x: String) {
       this.execute(new <undefinedtype>(x));// 14 15
    }// 18
 
-   fun testCaptureIntIterationValue(x: Iterable<Integer>) {
+   public fun testCaptureIntIterationValue(x: Iterable<Int>) {
       var var2: Iterator = x.iterator();// 21
 
       while (var2.hasNext()) {
-         this.execute(new <undefinedtype>((var2.next() as Number).intValue()));// 22
+         this.execute(new <undefinedtype>((var2.next() as java.lang.Number).intValue()));// 22
       }
    }// 26
 
-   fun testCaptureObjectIterationValue(x: Iterable<String>) {
-      for (String i : x) {// 29
+   public fun testCaptureObjectIterationValue(x: Iterable<String>) {
+      for (java.lang.String i : x) {// 29
          this.execute(new <undefinedtype>(i));// 30
       }
    }// 34
 
-   fun testCaptureMutableInt(x: Int) {
+   public fun testCaptureMutableInt(x: Int) {
       var y: IntRef = new IntRef();// 37
       y.element = x;
       this.execute(new <undefinedtype>(y));// 38
@@ -48,7 +49,7 @@ open class TestNonInlineLambda {
       this.execute(new <undefinedtype>(y));// 54
    }// 57
 
-   fun testCaptureMutableObject(x: String) {
+   public fun testCaptureMutableObject(x: String) {
       var y: ObjectRef = new ObjectRef();// 60
       y.element = x;
       this.execute(new <undefinedtype>(y));// 61
@@ -62,14 +63,14 @@ open class TestNonInlineLambda {
       this.execute(new <undefinedtype>(y));// 77
    }// 80
 
-   fun testCaptureAndMutateInt(x: Int) {
+   public fun testCaptureAndMutateInt(x: Int) {
       var y: IntRef = new IntRef();// 83
       this.execute(new <undefinedtype>(y));// 84
       y.element = 5 + x;// 89
       this.execute(new <undefinedtype>(y));// 90
    }// 95
 
-   fun testCaptureAndMutateString(x: String) {
+   public fun testCaptureAndMutateString(x: String) {
       var y: ObjectRef = new ObjectRef();// 98
       y.element = "";
       this.execute(new <undefinedtype>(y));// 99
@@ -77,23 +78,23 @@ open class TestNonInlineLambda {
       this.execute(new <undefinedtype>(y));// 106
    }// 112
 
-   fun testCapturePublicMutableIntField() {
+   public fun testCapturePublicMutableIntField() {
       this.execute(new <undefinedtype>(this));// 117
    }// 118
 
-   fun testCapturePublicMutableStringField() {
+   public fun testCapturePublicMutableStringField() {
       this.execute(new <undefinedtype>(this));// 123
    }// 124
 
-   fun testCapturePrivateMutableIntField() {
+   public fun testCapturePrivateMutableIntField() {
       this.execute(new <undefinedtype>(this));// 129
    }// 130
 
-   fun testCapturePrivateMutableStringField() {
+   public fun testCapturePrivateMutableStringField() {
       this.execute(new <undefinedtype>(this));// 135
    }// 136
 
-   open fun execute(block: () -> Unit) {
+   public open fun execute(block: () -> Unit) {
    }// 141
 
    @JvmStatic
@@ -110,492 +111,492 @@ open class TestNonInlineLambda {
 
    @JvmStatic
    @JvmSynthetic
-   fun `access$setPrivateStringField$p`(`$this`: TestNonInlineLambda, var1: String) {
+   fun `access$setPrivateStringField$p`(`$this`: TestNonInlineLambda, var1: java.lang.String) {
       `$this`.privateStringField = var1;
    }
 
    @JvmStatic
    @JvmSynthetic
-   fun `access$getPrivateStringField$p`(`$this`: TestNonInlineLambda): String {
+   fun `access$getPrivateStringField$p`(`$this`: TestNonInlineLambda): java.lang.String {
       return `$this`.privateStringField;// 3
    }
 }
 
 class 'pkg/TestNonInlineLambda' {
    method 'testCaptureInt (I)V' {
-      0      15
-      2      15
-      7      15
-      b      15
-      c      15
-      d      15
-      e      15
-      f      15
-      10      15
-      11      16
+      0      16
+      2      16
+      7      16
+      b      16
+      c      16
+      d      16
+      e      16
+      f      16
+      10      16
+      11      17
    }
 
    method 'testCaptureObject (Ljava/lang/String;)V' {
-      6      19
-      8      19
-      d      19
-      11      19
-      12      19
-      13      19
-      14      19
-      15      19
-      16      19
-      17      20
+      6      20
+      8      20
+      d      20
+      11      20
+      12      20
+      13      20
+      14      20
+      15      20
+      16      20
+      17      21
    }
 
    method 'testCaptureIntIterationValue (Ljava/lang/Iterable;)V' {
-      6      23
-      7      23
-      8      23
-      9      23
-      a      23
-      b      23
-      c      23
-      d      25
-      e      25
-      f      25
-      10      25
-      11      25
-      12      25
-      16      26
-      17      26
-      18      26
-      19      26
-      1a      26
-      1b      26
-      1c      26
-      1d      26
-      1e      26
-      1f      26
-      20      26
-      21      26
-      23      26
-      28      26
-      2c      26
-      2d      26
-      2e      26
-      2f      26
-      30      26
-      31      26
-      35      28
+      6      24
+      7      24
+      8      24
+      9      24
+      a      24
+      b      24
+      c      24
+      d      26
+      e      26
+      f      26
+      10      26
+      11      26
+      12      26
+      16      27
+      17      27
+      18      27
+      19      27
+      1a      27
+      1b      27
+      1c      27
+      1d      27
+      1e      27
+      1f      27
+      20      27
+      21      27
+      23      27
+      28      27
+      2c      27
+      2d      27
+      2e      27
+      2f      27
+      30      27
+      31      27
+      35      29
    }
 
    method 'testCaptureObjectIterationValue (Ljava/lang/Iterable;)V' {
-      6      31
-      7      31
-      8      31
-      9      31
-      a      31
-      b      31
-      c      31
-      16      31
-      17      31
-      18      31
-      19      31
-      1a      31
-      1b      31
-      1c      31
-      1d      31
-      1e      31
-      1f      31
-      20      32
-      25      32
-      29      32
-      2a      32
-      2b      32
-      2c      32
-      2d      32
-      2e      32
-      32      34
+      6      32
+      7      32
+      8      32
+      9      32
+      a      32
+      b      32
+      c      32
+      16      32
+      17      32
+      18      32
+      19      32
+      1a      32
+      1b      32
+      1c      32
+      1d      32
+      1e      32
+      1f      32
+      20      33
+      25      33
+      29      33
+      2a      33
+      2b      33
+      2c      33
+      2d      33
+      2e      33
+      32      35
    }
 
    method 'testCaptureMutableInt (I)V' {
-      7      37
-      8      38
-      9      38
-      a      38
-      b      38
-      c      38
-      d      39
-      12      39
-      16      39
-      17      39
-      18      39
-      19      39
-      1a      39
-      1b      39
-      1c      40
-      1d      40
-      1e      40
-      1f      40
-      20      40
-      24      40
-      28      41
-      2d      41
-      31      41
-      32      41
-      33      41
-      34      41
-      35      41
-      36      41
-      37      42
-      3c      42
-      3d      42
-      3e      42
-      40      42
-      41      42
-      42      42
-      43      43
-      48      43
-      4c      43
-      4d      43
-      4e      43
-      4f      43
-      50      43
-      51      43
-      52      44
-      53      44
-      54      44
-      55      44
-      56      44
-      57      44
-      58      45
-      5d      45
-      61      45
-      62      45
-      63      45
-      64      45
-      65      45
-      66      45
-      67      46
-      6c      46
-      6e      46
-      6f      46
-      70      46
-      71      47
-      76      47
-      7a      47
-      7b      47
-      7c      47
-      7d      47
-      7e      47
-      7f      47
-      80      48
+      7      38
+      8      39
+      9      39
+      a      39
+      b      39
+      c      39
+      d      40
+      12      40
+      16      40
+      17      40
+      18      40
+      19      40
+      1a      40
+      1b      40
+      1c      41
+      1d      41
+      1e      41
+      1f      41
+      20      41
+      24      41
+      28      42
+      2d      42
+      31      42
+      32      42
+      33      42
+      34      42
+      35      42
+      36      42
+      37      43
+      3c      43
+      3d      43
+      3e      43
+      40      43
+      41      43
+      42      43
+      43      44
+      48      44
+      4c      44
+      4d      44
+      4e      44
+      4f      44
+      50      44
+      51      44
+      52      45
+      53      45
+      54      45
+      55      45
+      56      45
+      57      45
+      58      46
+      5d      46
+      61      46
+      62      46
+      63      46
+      64      46
+      65      46
+      66      46
+      67      47
+      6c      47
+      6e      47
+      6f      47
+      70      47
+      71      48
+      76      48
+      7a      48
+      7b      48
+      7c      48
+      7d      48
+      7e      48
+      7f      48
+      80      49
    }
 
    method 'testCaptureMutableObject (Ljava/lang/String;)V' {
-      d      51
-      e      52
-      f      52
-      10      52
-      11      52
-      12      52
-      13      53
-      18      53
-      1c      53
-      1d      53
-      1e      53
-      1f      53
-      20      53
-      21      53
-      22      54
-      23      54
-      24      54
-      25      54
-      26      54
-      27      54
-      28      54
-      29      54
-      2a      54
-      2b      54
-      2c      54
-      2d      54
-      2e      54
-      2f      55
-      34      55
-      38      55
-      39      55
-      3a      55
-      3b      55
-      3c      55
-      3d      55
-      3e      56
-      3f      56
-      40      56
-      41      56
-      42      56
-      43      56
-      44      56
-      45      56
-      46      56
-      47      56
-      48      56
-      49      56
-      4a      56
-      4b      56
-      4c      56
-      4d      56
-      4e      56
-      4f      56
-      50      56
-      51      56
-      52      56
-      53      57
-      58      57
-      5c      57
-      5d      57
-      5e      57
-      5f      57
-      60      57
-      61      57
-      62      58
-      63      58
-      64      58
-      65      58
-      66      58
-      67      58
-      68      59
-      6d      59
-      71      59
-      72      59
-      73      59
-      74      59
-      75      59
-      76      59
-      77      60
-      78      60
-      79      60
-      7a      60
-      7b      60
-      7c      60
-      7d      60
-      7e      60
-      7f      60
-      80      60
-      81      60
-      82      60
-      83      60
-      84      60
-      85      61
-      8a      61
-      8e      61
-      8f      61
-      90      61
-      91      61
-      92      61
-      93      61
-      94      62
+      d      52
+      e      53
+      f      53
+      10      53
+      11      53
+      12      53
+      13      54
+      18      54
+      1c      54
+      1d      54
+      1e      54
+      1f      54
+      20      54
+      21      54
+      22      55
+      23      55
+      24      55
+      25      55
+      26      55
+      27      55
+      28      55
+      29      55
+      2a      55
+      2b      55
+      2c      55
+      2d      55
+      2e      55
+      2f      56
+      34      56
+      38      56
+      39      56
+      3a      56
+      3b      56
+      3c      56
+      3d      56
+      3e      57
+      3f      57
+      40      57
+      41      57
+      42      57
+      43      57
+      44      57
+      45      57
+      46      57
+      47      57
+      48      57
+      49      57
+      4a      57
+      4b      57
+      4c      57
+      4d      57
+      4e      57
+      4f      57
+      50      57
+      51      57
+      52      57
+      53      58
+      58      58
+      5c      58
+      5d      58
+      5e      58
+      5f      58
+      60      58
+      61      58
+      62      59
+      63      59
+      64      59
+      65      59
+      66      59
+      67      59
+      68      60
+      6d      60
+      71      60
+      72      60
+      73      60
+      74      60
+      75      60
+      76      60
+      77      61
+      78      61
+      79      61
+      7a      61
+      7b      61
+      7c      61
+      7d      61
+      7e      61
+      7f      61
+      80      61
+      81      61
+      82      61
+      83      61
+      84      61
+      85      62
+      8a      62
+      8e      62
+      8f      62
+      90      62
+      91      62
+      92      62
+      93      62
+      94      63
    }
 
    method 'testCaptureAndMutateInt (I)V' {
-      7      65
-      8      66
-      d      66
-      11      66
-      12      66
-      13      66
-      14      66
-      15      66
-      16      66
-      17      67
-      18      67
-      19      67
-      1a      67
-      1b      67
-      1c      67
-      1d      67
-      1e      68
-      23      68
-      27      68
-      28      68
-      29      68
-      2a      68
-      2b      68
-      2c      68
-      2d      69
+      7      66
+      8      67
+      d      67
+      11      67
+      12      67
+      13      67
+      14      67
+      15      67
+      16      67
+      17      68
+      18      68
+      19      68
+      1a      68
+      1b      68
+      1c      68
+      1d      68
+      1e      69
+      23      69
+      27      69
+      28      69
+      29      69
+      2a      69
+      2b      69
+      2c      69
+      2d      70
    }
 
    method 'testCaptureAndMutateString (Ljava/lang/String;)V' {
-      d      72
-      e      73
-      f      73
-      10      73
-      11      73
-      12      73
-      13      73
-      14      74
-      19      74
-      1d      74
-      1e      74
-      1f      74
-      20      74
-      21      74
-      22      74
-      23      75
-      24      75
-      25      75
-      26      75
-      27      75
-      28      75
-      29      75
-      2a      75
-      2b      75
-      2c      75
-      2d      76
-      32      76
-      36      76
-      37      76
-      38      76
-      39      76
-      3a      76
-      3b      76
-      3c      77
+      d      73
+      e      74
+      f      74
+      10      74
+      11      74
+      12      74
+      13      74
+      14      75
+      19      75
+      1d      75
+      1e      75
+      1f      75
+      20      75
+      21      75
+      22      75
+      23      76
+      24      76
+      25      76
+      26      76
+      27      76
+      28      76
+      29      76
+      2a      76
+      2b      76
+      2c      76
+      2d      77
+      32      77
+      36      77
+      37      77
+      38      77
+      39      77
+      3a      77
+      3b      77
+      3c      78
    }
 
    method 'testCapturePublicMutableIntField ()V' {
-      0      80
-      5      80
-      9      80
-      a      80
-      b      80
-      c      80
-      d      80
-      e      80
-      f      81
+      0      81
+      5      81
+      9      81
+      a      81
+      b      81
+      c      81
+      d      81
+      e      81
+      f      82
    }
 
    method 'testCapturePublicMutableStringField ()V' {
-      0      84
-      5      84
-      9      84
-      a      84
-      b      84
-      c      84
-      d      84
-      e      84
-      f      85
+      0      85
+      5      85
+      9      85
+      a      85
+      b      85
+      c      85
+      d      85
+      e      85
+      f      86
    }
 
    method 'testCapturePrivateMutableIntField ()V' {
-      0      88
-      5      88
-      9      88
-      a      88
-      b      88
-      c      88
-      d      88
-      e      88
-      f      89
+      0      89
+      5      89
+      9      89
+      a      89
+      b      89
+      c      89
+      d      89
+      e      89
+      f      90
    }
 
    method 'testCapturePrivateMutableStringField ()V' {
-      0      92
-      5      92
-      9      92
-      a      92
-      b      92
-      c      92
-      d      92
-      e      92
-      f      93
+      0      93
+      5      93
+      9      93
+      a      93
+      b      93
+      c      93
+      d      93
+      e      93
+      f      94
    }
 
    method 'execute (Lkotlin/jvm/functions/Function0;)V' {
-      6      96
+      6      97
    }
 
    method 'access$getPrivateIntField$p (Lpkg/TestNonInlineLambda;)I' {
-      0      101
-      1      101
-      2      101
-      3      101
-      4      101
+      0      102
+      1      102
+      2      102
+      3      102
+      4      102
    }
 
    method 'access$setPrivateIntField$p (Lpkg/TestNonInlineLambda;I)V' {
-      0      107
-      1      107
-      2      107
-      3      107
-      4      107
-      5      108
+      0      108
+      1      108
+      2      108
+      3      108
+      4      108
+      5      109
    }
 
    method 'access$setPrivateStringField$p (Lpkg/TestNonInlineLambda;Ljava/lang/String;)V' {
-      0      113
-      1      113
-      2      113
-      3      113
-      4      113
-      5      114
+      0      114
+      1      114
+      2      114
+      3      114
+      4      114
+      5      115
    }
 
    method 'access$getPrivateStringField$p (Lpkg/TestNonInlineLambda;)Ljava/lang/String;' {
-      0      119
-      1      119
-      2      119
-      3      119
-      4      119
+      0      120
+      1      120
+      2      120
+      3      120
+      4      120
    }
 }
 
 Lines mapping:
-3 <-> 120
-7 <-> 16
-8 <-> 16
-11 <-> 17
-14 <-> 20
-15 <-> 20
-18 <-> 21
-21 <-> 24
-22 <-> 27
-26 <-> 29
-29 <-> 32
-30 <-> 33
-34 <-> 35
-37 <-> 38
-38 <-> 40
-41 <-> 41
-42 <-> 42
-45 <-> 43
-46 <-> 44
-49 <-> 45
-50 <-> 46
-53 <-> 47
-54 <-> 48
-57 <-> 49
-60 <-> 52
-61 <-> 54
-64 <-> 55
-65 <-> 56
-68 <-> 57
-69 <-> 58
-72 <-> 59
-73 <-> 60
-76 <-> 61
-77 <-> 62
-80 <-> 63
-83 <-> 66
-84 <-> 67
-89 <-> 68
-90 <-> 69
-95 <-> 70
-98 <-> 73
-99 <-> 75
-105 <-> 76
-106 <-> 77
-112 <-> 78
-117 <-> 81
-118 <-> 82
-123 <-> 85
-124 <-> 86
-129 <-> 89
-130 <-> 90
-135 <-> 93
-136 <-> 94
-141 <-> 97
+3 <-> 121
+7 <-> 17
+8 <-> 17
+11 <-> 18
+14 <-> 21
+15 <-> 21
+18 <-> 22
+21 <-> 25
+22 <-> 28
+26 <-> 30
+29 <-> 33
+30 <-> 34
+34 <-> 36
+37 <-> 39
+38 <-> 41
+41 <-> 42
+42 <-> 43
+45 <-> 44
+46 <-> 45
+49 <-> 46
+50 <-> 47
+53 <-> 48
+54 <-> 49
+57 <-> 50
+60 <-> 53
+61 <-> 55
+64 <-> 56
+65 <-> 57
+68 <-> 58
+69 <-> 59
+72 <-> 60
+73 <-> 61
+76 <-> 62
+77 <-> 63
+80 <-> 64
+83 <-> 67
+84 <-> 68
+89 <-> 69
+90 <-> 70
+95 <-> 71
+98 <-> 74
+99 <-> 76
+105 <-> 77
+106 <-> 78
+112 <-> 79
+117 <-> 82
+118 <-> 83
+123 <-> 86
+124 <-> 87
+129 <-> 90
+130 <-> 91
+135 <-> 94
+136 <-> 95
+141 <-> 98
diff --git a/plugins/kotlin/testData/results/pkg/TestNothingReturns.dec b/plugins/kotlin/testData/results/pkg/TestNothingReturns.dec
index dcd0ebccc2..26e29647a7 100644
--- a/plugins/kotlin/testData/results/pkg/TestNothingReturns.dec
+++ b/plugins/kotlin/testData/results/pkg/TestNothingReturns.dec
@@ -1,23 +1,23 @@
 package pkg
 
 class TestNothingReturns {
-   fun loop(): Void {
+   public fun loop(): Nothing {
       while (true) {
          System.out.println("loop");// 6
       }
    }
 
-   fun test1(): Void {
+   public fun test1(): Nothing {
       this.loop();// 11
       throw new KotlinNothingValueException();
    }
 
-   fun test2(): Long {
+   public fun test2(): Long {
       this.test1();// 15
       throw new KotlinNothingValueException();
    }
 
-   fun test3(i: Int): Int {
+   public fun test3(i: Int): Int {
       if (i == 0) {// 19
          this.loop();// 20
          throw new KotlinNothingValueException();
@@ -26,18 +26,18 @@ class TestNothingReturns {
       }
    }
 
-   fun test4() {
+   public fun test4() {
       this.loop();// 27
       throw new KotlinNothingValueException();
    }
 
-   fun test5(s: String): String {
-      StringsKt.repeat(s as CharSequence, 5);// 32
+   public fun test5(s: String): String {
+      StringsKt.repeat(s as java.lang.CharSequence, 5);// 32
       this.loop();
       throw new KotlinNothingValueException();
    }
 
-   fun test6(s: String?): String {
+   public fun test6(s: String?): String {
       if (s == null) {// 36
          this.loop();
          throw new KotlinNothingValueException();
diff --git a/plugins/kotlin/testData/results/pkg/TestNullable.dec b/plugins/kotlin/testData/results/pkg/TestNullable.dec
index fefb588154..5cda97427b 100644
--- a/plugins/kotlin/testData/results/pkg/TestNullable.dec
+++ b/plugins/kotlin/testData/results/pkg/TestNullable.dec
@@ -1,14 +1,14 @@
 package pkg
 
 class TestNullable {
-   fun nullableParams(v: String, vn: String?) {
+   public fun nullableParams(v: String, vn: String?) {
    }// 6
 
-   fun nullableReturn(): String? {
+   public fun nullableReturn(): String? {
       return null;// 9
    }
 
-   fun nullableGenerics(v: MutableList<String>): MutableList<String>? {
+   public fun nullableGenerics(v: List<String?>): List<String?>? {
       return v;// 13
    }
 }
diff --git a/plugins/kotlin/testData/results/pkg/TestNullableOperator.dec b/plugins/kotlin/testData/results/pkg/TestNullableOperator.dec
index f52d0ff005..a8636ad41c 100644
--- a/plugins/kotlin/testData/results/pkg/TestNullableOperator.dec
+++ b/plugins/kotlin/testData/results/pkg/TestNullableOperator.dec
@@ -1,12 +1,12 @@
 package pkg
 
 class TestNullableOperator {
-   fun test(x: Int?): Int {
+   public fun test(x: Int?): Int {
       return x ?: 0;// 5
    }
 
-   fun test2(x: String?): String {
-      var var10000: String = x;// 9
+   public fun test2(x: String?): String {
+      var var10000: java.lang.String = x;// 9
       if (x == null) {
          var10000 = "default";
       }
@@ -14,7 +14,7 @@ class TestNullableOperator {
       return var10000;
    }
 
-   fun test2_1(x: Any?): Any {
+   public fun test2_1(x: Any?): Any {
       var var10000: Any = x;// 13
       if (x == null) {
          var10000 = "default";
@@ -23,7 +23,7 @@ class TestNullableOperator {
       return var10000;
    }
 
-   fun test2_2(x: Any?): Any {
+   public fun test2_2(x: Any?): Any {
       var var10000: Any = x;// 17
       if (x == null) {
          var10000 = "default";
@@ -32,7 +32,7 @@ class TestNullableOperator {
       return var10000;
    }
 
-   fun test3(x: Int?): Int {
+   public fun test3(x: Int?): Int {
       if (x != null) {// 21
          return x;
       } else {
@@ -40,13 +40,13 @@ class TestNullableOperator {
       }
    }
 
-   fun test4(x: Exception?) {
+   public fun test4(x: Exception?) {
       if (x != null) {// 25
          x.printStackTrace();
       }
    }// 26
 
-   fun test5(x: Exception?) {
+   public fun test5(x: Exception?) {
       var var10000: Unit;
       if (x != null) {// 29
          x.printStackTrace();
@@ -60,7 +60,7 @@ class TestNullableOperator {
       }
    }// 30
 
-   fun test6(x: Int?): Int {
+   public fun test6(x: Int?): Int {
       if (x != null) {// 33
          var y: Int = x;
          System.out.println(y);// 35
@@ -70,7 +70,7 @@ class TestNullableOperator {
       }
    }
 
-   fun test6_1(x: Int?) {
+   public fun test6_1(x: Int?) {
       if (x != null) {// 41
          System.out.println(x);// 43
       }
diff --git a/plugins/kotlin/testData/results/pkg/TestObject.dec b/plugins/kotlin/testData/results/pkg/TestObject.dec
index c2e3102094..3e7e6e42c7 100644
--- a/plugins/kotlin/testData/results/pkg/TestObject.dec
+++ b/plugins/kotlin/testData/results/pkg/TestObject.dec
@@ -1,6 +1,6 @@
 package pkg
 
-object TestObject {
+object TestObject private constructor() {
    @JvmStatic
    public TestObject INSTANCE = new TestObject();
 
@@ -8,45 +8,38 @@ object TestObject {
    public final val objectVal: Regex = new Regex("")
    private final var objectVar: Int = 42
 
-   fun TestObject() {
-   }// 3
 
-   fun objectFun() {
+   public fun objectFun() {
       objectVar += -1;// 5
    }// 6
 
    @JvmStatic
-   fun objectJvmStaticFun() {
+   public fun objectJvmStaticFun() {
       var var0: Int = objectVar++;// 16
    }// 17
 }
 
 class 'pkg/TestObject' {
-   method '<init> ()V' {
-      4      11
-   }
-
    method 'objectFun ()V' {
-      5      14
-      7      14
-      8      14
-      9      14
-      a      15
+      5      12
+      7      12
+      8      12
+      9      12
+      a      13
    }
 
    method 'objectJvmStaticFun ()V' {
-      4      19
-      5      19
-      6      19
-      7      19
-      a      19
-      e      20
+      4      17
+      5      17
+      6      17
+      7      17
+      a      17
+      e      18
    }
 }
 
 Lines mapping:
-3 <-> 12
-5 <-> 15
-6 <-> 16
-16 <-> 20
-17 <-> 21
+5 <-> 13
+6 <-> 14
+16 <-> 18
+17 <-> 19
diff --git a/plugins/kotlin/testData/results/pkg/TestParams.dec b/plugins/kotlin/testData/results/pkg/TestParams.dec
index dabf8830ba..d35e235e6b 100644
--- a/plugins/kotlin/testData/results/pkg/TestParams.dec
+++ b/plugins/kotlin/testData/results/pkg/TestParams.dec
@@ -1,29 +1,29 @@
 package pkg
 
 class TestParams {
-   fun printMessageUnit(message: String) {
+   public fun printMessageUnit(message: String) {
       System.out.println(message);// 5
    }// 6
 
-   fun printMessageVoid(message: String) {
+   public fun printMessageVoid(message: String) {
       System.out.println(message);// 9
    }// 10
 
-   fun multiply(x: Int, y: Int): Int {
+   public fun multiply(x: Int, y: Int): Int {
       return x * y;// 12
    }
 
-   fun multiplyBraces(x: Int, y: Int): Int {
+   public fun multiplyBraces(x: Int, y: Int): Int {
       return x * y;// 15
    }
 
-   fun printMessageWithPrefix(message: String, prefix: String) {
+   public fun printMessageWithPrefix(message: String, prefix: String) {
       System.out.println("[" + prefix + "] " + message);// 19
    }// 20
 
    @JvmStatic
    @JvmSynthetic
-   fun `printMessageWithPrefix$default`(var0: TestParams, var1: String, var2: String, var3: Int, var4: Any) {
+   fun `printMessageWithPrefix$default`(var0: TestParams, var1: java.lang.String, var2: java.lang.String, var3: Int, var4: Any) {
       if ((var3 and 2) != 0) {// 18
          var2 = "Info";
       }
@@ -31,7 +31,7 @@ class TestParams {
       var0.printMessageWithPrefix(var1, var2);
    }
 
-   fun callPrintMessage() {
+   public fun callPrintMessage() {
       printMessageWithPrefix$default(this, "Test", null, 2, null);// 23
       this.printMessageWithPrefix("Test", "Debug");// 24
    }// 25
diff --git a/plugins/kotlin/testData/results/pkg/TestPoorNames.dec b/plugins/kotlin/testData/results/pkg/TestPoorNames.dec
index 213c7117b9..2af7540612 100644
--- a/plugins/kotlin/testData/results/pkg/TestPoorNames.dec
+++ b/plugins/kotlin/testData/results/pkg/TestPoorNames.dec
@@ -4,19 +4,20 @@ class TestPoorNames {
    public final val `Dangerous property name?!`: String = "test"
    public final val `Property with spaces`: Int = 42
 
-   fun `Function with spaces`() {
+
+   public fun `Function with spaces`() {
    }// 5
 
-   fun `Dangerous function name?!`() {
+   public fun `Dangerous function name?!`() {
    }// 8
 
-   fun `functionWith$Dollar`() {
+   public fun `functionWith$Dollar`() {
    }// 14
 
-   fun functionWithParameters(var1: Int, var2: String) {
+   public fun functionWithParameters(`Parameter with spaces`: Int, `Dangerous parameter name?!`: String) {
    }// 17
 
-   fun test() {
+   public fun test() {
       new TestPoorNames.Class with spaces();
       this.Dangerous function name?!();// 23
       this.functionWithParameters(42, "test");// 24
@@ -28,45 +29,45 @@ class TestPoorNames {
 
 class 'pkg/TestPoorNames' {
    method 'Function with spaces ()V' {
-      0      7
+      0      8
    }
 
    method 'Dangerous function name?! ()V' {
-      0      10
+      0      11
    }
 
    method 'functionWith$Dollar ()V' {
-      0      13
+      0      14
    }
 
    method 'functionWithParameters (ILjava/lang/String;)V' {
-      6      16
+      6      17
    }
 
    method 'test ()V' {
-      8      20
-      9      20
-      a      20
-      b      20
-      c      21
-      d      21
-      e      21
-      f      21
-      10      21
-      11      21
-      12      21
-      13      21
-      14      22
+      8      21
+      9      21
+      a      21
+      b      21
+      c      22
+      d      22
+      e      22
+      f      22
+      10      22
+      11      22
+      12      22
+      13      22
+      14      23
    }
 }
 
 Lines mapping:
-5 <-> 8
-8 <-> 11
-14 <-> 14
-17 <-> 17
-23 <-> 21
-24 <-> 22
-25 <-> 23
+5 <-> 9
+8 <-> 12
+14 <-> 15
+17 <-> 18
+23 <-> 22
+24 <-> 23
+25 <-> 24
 Not mapped:
 22
diff --git a/plugins/kotlin/testData/results/pkg/TestReflection.dec b/plugins/kotlin/testData/results/pkg/TestReflection.dec
index eafa653fc3..9126567a5b 100644
--- a/plugins/kotlin/testData/results/pkg/TestReflection.dec
+++ b/plugins/kotlin/testData/results/pkg/TestReflection.dec
@@ -4,25 +4,25 @@ import kotlin.jvm.functions.Function1
 import kotlin.reflect.KFunction
 
 class TestReflection {
-   fun testClassReference() {
+   public fun testClassReference() {
       System.out.println(TestReflection::class);// 5
       System.out.println(TestReflection::class.java);// 6
    }// 7
 
-   fun testPrimitiveWrapper() {
+   public fun testPrimitiveWrapper() {
       System.out.println(Int::class);// 10
       System.out.println(Integer::class.javaObjectType);// 11
    }// 12
 
-   fun testPrimitiveType() {
+   public fun testPrimitiveType() {
       System.out.println(Int::class.javaPrimitiveType);// 15
    }// 16
 
-   fun testInferredPrimitive() {
+   public fun testInferredPrimitive() {
       System.out.println(Int::class.javaPrimitiveType);// 19
    }// 20
 
-   fun testFunctionReference() {
+   public fun testFunctionReference() {
       var f: KFunction = <unknownclass>.INSTANCE as KFunction;// 23
       System.out.println(<unknownclass>.INSTANCE as KFunction);// 24
       (f as Function1).invoke(new TestReflection());// 25
diff --git a/plugins/kotlin/testData/results/pkg/TestSafeCasts.dec b/plugins/kotlin/testData/results/pkg/TestSafeCasts.dec
index 875bbb1db8..f8429bc7fe 100644
--- a/plugins/kotlin/testData/results/pkg/TestSafeCasts.dec
+++ b/plugins/kotlin/testData/results/pkg/TestSafeCasts.dec
@@ -1,7 +1,7 @@
 package pkg
 
 class TestSafeCasts {
-   fun test(obj: Any): Boolean {
+   public fun test(obj: Any): Boolean {
       var t: Int = obj as? Integer;// 5
       if ((obj as? Integer) != null) {// 7
          if (t == 1) {
@@ -12,7 +12,7 @@ class TestSafeCasts {
       return false;
    }
 
-   fun testTestBefore(obj: Any): Boolean? {
+   public fun testTestBefore(obj: Any): Boolean? {
       if (obj !is Integer) {// 11
          return null;// 12
       } else {
@@ -27,15 +27,15 @@ class TestSafeCasts {
       }
    }
 
-   fun testHardIncompatible(obj: Int): Boolean {
-      return (obj as? String) == "1";// 21 23
+   public fun testHardIncompatible(obj: Int): Boolean {
+      return (obj as? java.lang.String) == "1";// 21 23
    }
 
-   fun testSmartCastIncompatible(obj: Any): Boolean {
-      return obj is Integer && (obj as? String) == "1";// 27 31 33
+   public fun testSmartCastIncompatible(obj: Any): Boolean {
+      return obj is Integer && (obj as? java.lang.String) == "1";// 27 31 33
    }
 
-   fun testCastNonNullToNullable(obj: Any): Boolean {
+   public fun testCastNonNullToNullable(obj: Any): Boolean {
       var t: Int = obj as? Integer;// 37
       if ((obj as? Integer) != null) {// 39
          if (t == 1) {
@@ -46,7 +46,7 @@ class TestSafeCasts {
       return false;
    }
 
-   fun testBeforeNonNullToNullable(obj: Any): Boolean? {
+   public fun testBeforeNonNullToNullable(obj: Any): Boolean? {
       if (obj !is Integer) {// 43
          return null;// 44
       } else {
@@ -61,7 +61,7 @@ class TestSafeCasts {
       }
    }
 
-   fun testCastNullableToNullable(obj: Any?): Boolean {
+   public fun testCastNullableToNullable(obj: Any?): Boolean {
       var t: Int = obj as? Integer;// 53
       if ((obj as? Integer) != null) {// 55
          if (t == 1) {
@@ -72,7 +72,7 @@ class TestSafeCasts {
       return false;
    }
 
-   fun testBeforeNullableToNullable(obj: Any?): Boolean? {
+   public fun testBeforeNullableToNullable(obj: Any?): Boolean? {
       if (obj != null && obj !is Integer) {// 59
          return null;// 60
       } else {
diff --git a/plugins/kotlin/testData/results/pkg/TestSealedHierarchy.dec b/plugins/kotlin/testData/results/pkg/TestSealedHierarchy.dec
index 46ecc356a4..2e488973aa 100644
--- a/plugins/kotlin/testData/results/pkg/TestSealedHierarchy.dec
+++ b/plugins/kotlin/testData/results/pkg/TestSealedHierarchy.dec
@@ -1,74 +1,43 @@
 package pkg
 
-import kotlin.jvm.internal.DefaultConstructorMarker
-
-sealed class TestSealedHierarchy {
-   fun TestSealedHierarchy() {
-   }// 3
-
-   @JvmSynthetic
-   open fun TestSealedHierarchy(`$constructor_marker`: DefaultConstructorMarker) {
-      this();
-   }
-
-   class TestClass : TestSealedHierarchy {
+sealed class TestSealedHierarchy protected constructor() {
+   class TestClass(x: Int) : TestSealedHierarchy() {// 5
       public final val x: Int
 
-      fun TestClass(x: Int) {
-         super(null);// 5
+      init {
          this.x = x;
       }
    }
 
-   object TestObject : TestSealedHierarchy {
+   object TestObject private constructor() : TestSealedHierarchy() {// 4
       @JvmStatic
       public TestSealedHierarchy.TestObject INSTANCE = new TestSealedHierarchy.TestObject();
 
-      fun TestObject() {
-         super(null);// 4
-      }
-   }
-}
-
-class 'pkg/TestSealedHierarchy' {
-   method '<init> ()V' {
-      4      6
-   }
-
-   method '<init> (Lkotlin/jvm/internal/DefaultConstructorMarker;)V' {
-      1      10
-      2      10
-      3      10
-      4      11
    }
 }
 
 class 'pkg/TestSealedHierarchy$TestClass' {
    method '<init> (I)V' {
-      1      17
-      2      17
-      3      17
-      4      17
-      5      18
-      6      18
-      7      18
-      8      18
-      9      18
-      a      19
+      2      3
+      3      3
+      4      3
+      5      7
+      6      7
+      7      7
+      8      7
+      9      7
+      a      8
    }
 }
 
 class 'pkg/TestSealedHierarchy$TestObject' {
    method '<init> ()V' {
-      1      27
-      2      27
-      3      27
-      4      27
-      5      28
+      2      11
+      3      11
+      4      11
    }
 }
 
 Lines mapping:
-3 <-> 7
-4 <-> 28
-5 <-> 18
+4 <-> 12
+5 <-> 4
diff --git a/plugins/kotlin/testData/results/pkg/TestShadowParam.dec b/plugins/kotlin/testData/results/pkg/TestShadowParam.dec
index 9bf21e3239..ac3433aacf 100644
--- a/plugins/kotlin/testData/results/pkg/TestShadowParam.dec
+++ b/plugins/kotlin/testData/results/pkg/TestShadowParam.dec
@@ -1,7 +1,7 @@
 package pkg
 
 class TestShadowParam {
-   fun test(x: Int) {
+   public fun test(x: Int) {
       var xx: Int = x - 1;// 5 6
       System.out.println(x - 1);// 7
       if (xx < 0) {// 8
diff --git a/plugins/kotlin/testData/results/pkg/TestSmartCasts.dec b/plugins/kotlin/testData/results/pkg/TestSmartCasts.dec
index c3e0ef24f2..0d58d4ecce 100644
--- a/plugins/kotlin/testData/results/pkg/TestSmartCasts.dec
+++ b/plugins/kotlin/testData/results/pkg/TestSmartCasts.dec
@@ -1,11 +1,9 @@
 package pkg
 
-import kotlin.jvm.internal.DefaultConstructorMarker
-
 class TestSmartCasts {
-   fun testWhen(o: Any?): String {
-      if (o is String) {// 19 20
-         return o as String;// 21
+   public fun testWhen(o: Any?): String {
+      if (o is java.lang.String) {// 19 20
+         return o as java.lang.String;// 21
       } else {
          if (o is TestSmartCasts.A.B) {// 24
             System.out.println("B: " + o);
@@ -33,11 +31,11 @@ class TestSmartCasts {
       }
    }
 
-   fun testIf(a: Any?): String {
+   public fun testIf(a: Any?): String {
       return if (a !is TestSmartCasts.A.B && a !is TestSmartCasts.A.C) "else: " + a else (a as TestSmartCasts.A).test();// 35 36 39
    }
 
-   fun testIf2(a: Any?): String {
+   public fun testIf2(a: Any?): String {
       if (a is TestSmartCasts.A) {// 43
          if (a is TestSmartCasts.A.B || a is TestSmartCasts.A.C) {// 44
             System.out.println((a as TestSmartCasts.A).test());// 45
@@ -58,19 +56,19 @@ class TestSmartCasts {
       return "else: " + a;// 60
    }
 
-   fun testCast(a: Any?) {
+   public fun testCast(a: Any?) {
       System.out.println(a);// 64
       if (a == null) {// 65
          throw new NullPointerException("null cannot be cast to non-null type kotlin.String");
       } else {
          System.out.println("hello");// 66
          System.out.println(a);// 67
-         (a as String).charAt(0);// 68
-         System.out.println((a as String).charAt(0));// 69
+         (a as java.lang.String).charAt(0);// 68
+         System.out.println((a as java.lang.String).charAt(0));// 69
       }
    }// 70
 
-   fun testSealedIf(a: TestSmartCasts.A): String {
+   public fun testSealedIf(a: pkg.TestSmartCasts.A): String {
       if (a is TestSmartCasts.A.B) {// 73
          return (a as TestSmartCasts.A.B).testB();// 74
       } else {
@@ -78,51 +76,36 @@ class TestSmartCasts {
       }
    }
 
-   fun testDoubleType(t: MutableList<String>): String {
-      return if (t is TestSmartCasts.X) (t as TestSmartCasts.X).woo(t as Iterable<?>) else t.get(0) as String;// 83 84 87
+   public fun testDoubleType(t: List<String>): String {
+      return if (t is TestSmartCasts.X) (t as TestSmartCasts.X).woo(t as java.lang.Iterable<?>) else t.get(0) as java.lang.String;// 83 84 87
    }
 
-   sealed class A {
-      fun A() {
-      }// 7
-
-      fun test(): String {
+   sealed class A protected constructor() {
+      public fun test(): String {
          return "";// 15
       }
 
-      @JvmSynthetic
-      open fun A(`$constructor_marker`: DefaultConstructorMarker) {
-         this();
-      }
-
-      class B : TestSmartCasts.A {
-         fun B() {
-            super(null);// 8
-         }
-
-         fun testB(): String {
+      class B : TestSmartCasts.A() {// 8
+         public fun testB(): String {
             return "B";// 9
          }
       }
 
-      class C : TestSmartCasts.A {
-         fun C() {
-            super(null);// 11
-         }
-
-         fun testC(): String {
+      class C : TestSmartCasts.A() {// 11
+         public fun testC(): String {
             return "C";// 12
          }
       }
    }
 
    interface X {
-      fun woo(var1: Iterable<?>): String
+      public open fun Iterable<*>.woo(): String {
+      }
 
       // $VF: Class flags could not be determined
       internal class DefaultImpls {
          @JvmStatic
-         fun woo(var0: TestSmartCasts.X, receiver: Iterable<?>): String {
+         fun woo(var0: TestSmartCasts.X, receiver: MutableIterable<*>): java.lang.String {
             return "A";// 5
          }
       }
@@ -131,448 +114,432 @@ class TestSmartCasts {
 
 class 'pkg/TestSmartCasts' {
    method 'testWhen (Ljava/lang/Object;)Ljava/lang/String;' {
-      0      6
-      2      6
-      3      6
-      4      6
-      5      6
-      6      6
-      9      7
-      a      7
-      b      7
-      c      7
-      d      7
-      e      9
-      f      9
-      10      9
-      11      9
-      12      9
-      15      10
-      16      10
-      17      10
-      18      10
-      19      10
-      1a      10
-      1b      10
-      1c      10
-      1d      10
-      1f      10
-      20      10
-      21      10
-      25      12
-      29      12
-      2c      24
-      2d      24
-      2e      24
-      2f      24
-      30      24
-      31      24
-      32      24
-      33      24
-      34      24
-      36      24
-      37      24
-      38      24
-      3c      13
-      3d      13
-      3e      13
-      3f      13
-      40      13
-      43      14
-      44      14
-      45      14
-      46      14
-      47      14
-      48      14
-      49      14
-      4a      14
-      4b      14
-      4c      14
-      4d      14
-      4e      14
-      4f      14
-      50      14
-      51      14
-      52      14
-      53      14
-      54      14
-      55      14
-      56      14
-      57      14
-      58      14
-      59      14
-      5a      14
-      5b      14
-      5c      14
-      5d      14
-      5e      14
-      5f      17
-      60      17
-      63      18
-      64      18
-      65      18
-      66      21
-      67      21
-      68      21
-      69      21
-      6a      21
-      6b      21
-      6c      21
-      6d      27
-      6f      27
-      77      28
-      78      28
-      7c      28
-      7d      30
-      7e      30
-      7f      30
-      80      30
-      81      30
-      82      30
-      83      30
+      0      4
+      2      4
+      3      4
+      4      4
+      5      4
+      6      4
+      9      5
+      a      5
+      b      5
+      c      5
+      d      5
+      e      7
+      f      7
+      10      7
+      11      7
+      12      7
+      15      8
+      16      8
+      17      8
+      18      8
+      19      8
+      1a      8
+      1b      8
+      1c      8
+      1d      8
+      1f      8
+      20      8
+      21      8
+      25      10
+      29      10
+      2c      22
+      2d      22
+      2e      22
+      2f      22
+      30      22
+      31      22
+      32      22
+      33      22
+      34      22
+      36      22
+      37      22
+      38      22
+      3c      11
+      3d      11
+      3e      11
+      3f      11
+      40      11
+      43      12
+      44      12
+      45      12
+      46      12
+      47      12
+      48      12
+      49      12
+      4a      12
+      4b      12
+      4c      12
+      4d      12
+      4e      12
+      4f      12
+      50      12
+      51      12
+      52      12
+      53      12
+      54      12
+      55      12
+      56      12
+      57      12
+      58      12
+      59      12
+      5a      12
+      5b      12
+      5c      12
+      5d      12
+      5e      12
+      5f      15
+      60      15
+      63      16
+      64      16
+      65      16
+      66      19
+      67      19
+      68      19
+      69      19
+      6a      19
+      6b      19
+      6c      19
+      6d      25
+      6f      25
+      77      26
+      78      26
+      7c      26
+      7d      28
+      7e      28
+      7f      28
+      80      28
+      81      28
+      82      28
+      83      28
    }
 
    method 'testIf (Ljava/lang/Object;)Ljava/lang/String;' {
-      0      36
-      4      36
-      7      36
-      b      36
-      e      36
-      f      36
-      10      36
-      11      36
-      12      36
-      13      36
-      14      36
-      16      36
-      17      36
-      18      36
-      19      36
-      1a      36
-      1b      36
+      0      34
+      4      34
+      7      34
+      b      34
+      e      34
+      f      34
+      10      34
+      11      34
+      12      34
+      13      34
+      14      34
+      16      34
+      17      34
+      18      34
+      19      34
+      1a      34
+      1b      34
    }
 
    method 'testIf2 (Ljava/lang/Object;)Ljava/lang/String;' {
-      0      40
-      1      40
-      2      40
-      3      40
-      4      40
-      7      41
-      8      41
-      9      41
-      a      41
-      b      41
-      e      41
-      f      41
-      10      41
-      11      41
-      12      41
-      15      42
-      16      42
-      17      42
-      18      42
-      19      42
-      1a      42
-      1b      42
-      1c      42
-      1d      42
-      1e      42
-      20      42
-      23      45
-      24      45
-      25      45
-      26      45
-      27      45
-      2a      46
-      2b      46
-      2c      46
-      2d      46
-      2e      46
-      31      47
-      32      47
-      33      47
-      34      47
-      35      47
-      36      47
-      37      47
-      38      47
-      39      47
-      3a      47
-      3c      47
-      3d      47
-      3e      47
-      3f      48
-      40      48
-      41      48
-      42      48
-      43      48
-      44      48
-      45      48
-      46      48
-      47      48
-      48      48
-      4a      48
-      4d      51
-      4e      51
-      4f      51
-      50      51
-      51      51
-      54      51
-      55      51
-      56      51
-      57      51
-      58      51
-      59      51
-      5a      51
-      5b      51
-      5c      51
-      60      51
-      63      51
-      64      51
-      65      51
-      66      51
-      67      51
-      6a      52
-      6b      52
-      6c      52
-      6d      52
-      6e      52
-      6f      52
-      70      52
-      71      52
-      72      52
-      73      52
-      75      52
-      78      57
-      79      57
-      7a      57
-      7b      57
-      7c      57
-      7d      57
-      7e      57
+      0      38
+      1      38
+      2      38
+      3      38
+      4      38
+      7      39
+      8      39
+      9      39
+      a      39
+      b      39
+      e      39
+      f      39
+      10      39
+      11      39
+      12      39
+      15      40
+      16      40
+      17      40
+      18      40
+      19      40
+      1a      40
+      1b      40
+      1c      40
+      1d      40
+      1e      40
+      20      40
+      23      43
+      24      43
+      25      43
+      26      43
+      27      43
+      2a      44
+      2b      44
+      2c      44
+      2d      44
+      2e      44
+      31      45
+      32      45
+      33      45
+      34      45
+      35      45
+      36      45
+      37      45
+      38      45
+      39      45
+      3a      45
+      3c      45
+      3d      45
+      3e      45
+      3f      46
+      40      46
+      41      46
+      42      46
+      43      46
+      44      46
+      45      46
+      46      46
+      47      46
+      48      46
+      4a      46
+      4d      49
+      4e      49
+      4f      49
+      50      49
+      51      49
+      54      49
+      55      49
+      56      49
+      57      49
+      58      49
+      59      49
+      5a      49
+      5b      49
+      5c      49
+      60      49
+      63      49
+      64      49
+      65      49
+      66      49
+      67      49
+      6a      50
+      6b      50
+      6c      50
+      6d      50
+      6e      50
+      6f      50
+      70      50
+      71      50
+      72      50
+      73      50
+      75      50
+      78      55
+      79      55
+      7a      55
+      7b      55
+      7c      55
+      7d      55
+      7e      55
    }
 
    method 'testCast (Ljava/lang/Object;)V' {
-      0      61
-      1      61
-      2      61
-      3      61
-      4      61
-      5      61
-      6      61
-      7      62
-      9      62
-      11      63
-      12      63
-      16      63
-      1b      65
-      1c      65
-      1d      65
-      1e      65
-      1f      65
-      21      65
-      22      65
-      23      65
-      24      66
-      25      66
-      26      66
-      27      66
-      28      66
-      29      66
-      2a      66
-      2b      67
-      2c      67
-      2d      67
-      2e      67
-      2f      67
-      30      67
-      31      67
-      32      67
-      34      68
-      35      68
-      36      68
-      37      68
-      38      68
-      39      68
-      3a      68
-      3b      68
-      3d      68
-      3e      68
-      3f      68
-      40      68
-      41      68
-      42      68
-      43      68
-      44      70
+      0      59
+      1      59
+      2      59
+      3      59
+      4      59
+      5      59
+      6      59
+      7      60
+      9      60
+      11      61
+      12      61
+      16      61
+      1b      63
+      1c      63
+      1d      63
+      1e      63
+      1f      63
+      21      63
+      22      63
+      23      63
+      24      64
+      25      64
+      26      64
+      27      64
+      28      64
+      29      64
+      2a      64
+      2b      65
+      2c      65
+      2d      65
+      2e      65
+      2f      65
+      30      65
+      31      65
+      32      65
+      34      66
+      35      66
+      36      66
+      37      66
+      38      66
+      39      66
+      3a      66
+      3b      66
+      3d      66
+      3e      66
+      3f      66
+      40      66
+      41      66
+      42      66
+      43      66
+      44      68
    }
 
    method 'testSealedIf (Lpkg/TestSmartCasts$A;)Ljava/lang/String;' {
-      6      73
-      7      73
-      8      73
-      9      73
-      a      73
-      d      74
-      e      74
-      f      74
-      10      74
-      11      74
-      12      74
-      13      74
-      14      74
-      15      76
-      16      76
-      17      76
-      18      76
-      19      76
-      1c      76
-      1d      76
-      1e      76
-      1f      76
-      20      76
-      21      76
-      22      76
-      24      76
-      25      76
-      26      76
-      27      76
+      6      71
+      7      71
+      8      71
+      9      71
+      a      71
+      d      72
+      e      72
+      f      72
+      10      72
+      11      72
+      12      72
+      13      72
+      14      72
+      15      74
+      16      74
+      17      74
+      18      74
+      19      74
+      1c      74
+      1d      74
+      1e      74
+      1f      74
+      20      74
+      21      74
+      22      74
+      24      74
+      25      74
+      26      74
+      27      74
    }
 
    method 'testDoubleType (Ljava/util/List;)Ljava/lang/String;' {
-      6      81
-      7      81
-      8      81
-      9      81
-      a      81
-      d      81
-      11      81
-      12      81
-      13      81
-      14      81
-      15      81
-      16      81
-      17      81
-      18      81
-      19      81
-      1a      81
-      1b      81
-      1c      81
-      1d      81
-      1f      81
-      20      81
-      21      81
-      22      81
-      23      81
-      24      81
-      25      81
-      26      81
-      27      81
-      28      81
+      6      79
+      7      79
+      8      79
+      9      79
+      a      79
+      d      79
+      11      79
+      12      79
+      13      79
+      14      79
+      15      79
+      16      79
+      17      79
+      18      79
+      19      79
+      1a      79
+      1b      79
+      1c      79
+      1d      79
+      1f      79
+      20      79
+      21      79
+      22      79
+      23      79
+      24      79
+      25      79
+      26      79
+      27      79
+      28      79
    }
 }
 
 class 'pkg/TestSmartCasts$A' {
-   method '<init> ()V' {
-      4      86
-   }
-
    method 'test ()Ljava/lang/String;' {
-      0      89
-      1      89
-      2      89
-   }
-
-   method '<init> (Lkotlin/jvm/internal/DefaultConstructorMarker;)V' {
-      1      94
-      2      94
-      3      94
-      4      95
+      0      84
+      1      84
+      2      84
    }
 }
 
 class 'pkg/TestSmartCasts$A$B' {
    method '<init> ()V' {
-      1      99
-      2      99
-      3      99
-      4      99
-      5      100
+      2      87
+      3      87
+      4      87
    }
 
    method 'testB ()Ljava/lang/String;' {
-      0      103
-      1      103
-      2      103
+      0      89
+      1      89
+      2      89
    }
 }
 
 class 'pkg/TestSmartCasts$A$C' {
    method '<init> ()V' {
-      1      109
-      2      109
-      3      109
-      4      109
-      5      110
+      2      93
+      3      93
+      4      93
    }
 
    method 'testC ()Ljava/lang/String;' {
-      0      113
-      1      113
-      2      113
+      0      95
+      1      95
+      2      95
    }
 }
 
 class 'pkg/TestSmartCasts$X$DefaultImpls' {
    method 'woo (Lpkg/TestSmartCasts$X;Ljava/lang/Iterable;)Ljava/lang/String;' {
-      6      125
-      7      125
-      8      125
+      6      108
+      7      108
+      8      108
    }
 }
 
 Lines mapping:
-5 <-> 126
-7 <-> 87
-8 <-> 100
-9 <-> 104
-11 <-> 110
-12 <-> 114
-15 <-> 90
-19 <-> 7
-20 <-> 7
-21 <-> 8
-24 <-> 10
-25 <-> 13
-26 <-> 14
-27 <-> 18
-28 <-> 22
-31 <-> 28
-35 <-> 37
-36 <-> 37
-39 <-> 37
-43 <-> 41
-44 <-> 42
-45 <-> 43
-48 <-> 46
-49 <-> 47
-50 <-> 48
-51 <-> 49
-54 <-> 52
-55 <-> 53
-60 <-> 58
-64 <-> 62
-65 <-> 63
-66 <-> 66
-67 <-> 67
-68 <-> 68
-69 <-> 69
-70 <-> 71
-73 <-> 74
-74 <-> 75
-75 <-> 77
-76 <-> 77
-78 <-> 77
-83 <-> 82
-84 <-> 82
-87 <-> 82
+5 <-> 109
+8 <-> 88
+9 <-> 90
+11 <-> 94
+12 <-> 96
+15 <-> 85
+19 <-> 5
+20 <-> 5
+21 <-> 6
+24 <-> 8
+25 <-> 11
+26 <-> 12
+27 <-> 16
+28 <-> 20
+31 <-> 26
+35 <-> 35
+36 <-> 35
+39 <-> 35
+43 <-> 39
+44 <-> 40
+45 <-> 41
+48 <-> 44
+49 <-> 45
+50 <-> 46
+51 <-> 47
+54 <-> 50
+55 <-> 51
+60 <-> 56
+64 <-> 60
+65 <-> 61
+66 <-> 64
+67 <-> 65
+68 <-> 66
+69 <-> 67
+70 <-> 69
+73 <-> 72
+74 <-> 73
+75 <-> 75
+76 <-> 75
+78 <-> 75
+83 <-> 80
+84 <-> 80
+87 <-> 80
diff --git a/plugins/kotlin/testData/results/pkg/TestSynchronized.dec b/plugins/kotlin/testData/results/pkg/TestSynchronized.dec
index 4e27036e62..0d166bac19 100644
--- a/plugins/kotlin/testData/results/pkg/TestSynchronized.dec
+++ b/plugins/kotlin/testData/results/pkg/TestSynchronized.dec
@@ -1,8 +1,7 @@
 package pkg
 
 class TestSynchronized {
-   // $VF: Extended synchronized range to monitorexit
-   fun test() {
+   public fun test() {
       synchronized (this) {// 5
          System.out.println("Hello");// 6
       }
@@ -11,31 +10,31 @@ class TestSynchronized {
 
 class 'pkg/TestSynchronized' {
    method 'test ()V' {
-      0      5
-      2      5
-      3      5
-      7      6
-      8      6
-      9      6
-      a      6
-      b      6
-      d      6
-      e      6
-      f      6
-      17      8
-      18      8
-      19      8
-      1a      8
-      1b      8
-      1c      8
-      1d      8
-      1e      8
+      0      4
+      2      4
+      3      4
+      7      5
+      8      5
+      9      5
+      a      5
+      b      5
+      d      5
+      e      5
+      f      5
+      17      7
+      18      7
+      19      7
+      1a      7
+      1b      7
+      1c      7
+      1d      7
+      1e      7
    }
 }
 
 Lines mapping:
-5 <-> 6
-6 <-> 7
+5 <-> 5
+6 <-> 6
 Not mapped:
 7
 8
diff --git a/plugins/kotlin/testData/results/pkg/TestTailrecFunctions.dec b/plugins/kotlin/testData/results/pkg/TestTailrecFunctions.dec
index 6c30303995..39e7eeff61 100644
--- a/plugins/kotlin/testData/results/pkg/TestTailrecFunctions.dec
+++ b/plugins/kotlin/testData/results/pkg/TestTailrecFunctions.dec
@@ -1,7 +1,7 @@
 package pkg
 
 class TestTailrecFunctions {
-   fun sum(x: Long, sum: Long): Long {
+   public tailrec fun sum(x: Long, sum: Long): Long {
       var var5: TestTailrecFunctions = this;// 4
       var var6: Long = x;
       var var8: Long = sum;
@@ -17,11 +17,11 @@ class TestTailrecFunctions {
       return var8;
    }
 
-   fun testFinally() {
+   public tailrec fun testFinally() {
       label12: {
          try {
             ;
-         } catch (Throwable var2) {
+         } catch (java.lang.Throwable var2) {
             this.testFinally();// 13
          }
 
@@ -29,24 +29,24 @@ class TestTailrecFunctions {
       }
    }
 
-   fun testFinallyReturn(): Int {
+   public tailrec fun testFinallyReturn(): Int {
       try {
          ;
-      } catch (Throwable var2) {
+      } catch (java.lang.Throwable var2) {
          return this.testFinallyReturn();// 21
       }
 
       return this.testFinallyReturn();
    }
 
-   fun fooTry() {
+   public tailrec fun fooTry() {
       try {
          this.fooTry();// 27
-      } catch (Throwable var2) {// 29
+      } catch (java.lang.Throwable var2) {// 29
       }
    }// 31
 
-   fun testTryCatchFinally() {
+   public tailrec fun testTryCatchFinally() {
       label31: {
          label32: {
             try {
@@ -56,7 +56,7 @@ class TestTailrecFunctions {
                } catch (Exception var2) {// 36
                   this.testTryCatchFinally();// 37
                }
-            } catch (Throwable var3) {
+            } catch (java.lang.Throwable var3) {
                this.testTryCatchFinally();// 39
             }
 
@@ -68,7 +68,7 @@ class TestTailrecFunctions {
       }
    }
 
-   fun fastPow(x: Long, n: Long, acc: Long): Long {
+   public tailrec fun fastPow(x: Long, n: Long, acc: Long): Long {
       var var7: TestTailrecFunctions = this;
       var var8: Long = x;
       var var10: Long = n;
@@ -105,7 +105,7 @@ class TestTailrecFunctions {
       return var0.fastPow(var1, var3, var5);
    }
 
-   fun fastPow(x: Long, n: Long): Long {
+   public tailrec fun fastPow(x: Long, n: Long): Long {
       var var5: TestTailrecFunctions = this;// 49
       var var6: Long = x;
       var var8: Long = n;
diff --git a/plugins/kotlin/testData/results/pkg/TestTopLevelKt.dec b/plugins/kotlin/testData/results/pkg/TestTopLevelKt.dec
index bb9b18cb43..6c4f34d637 100644
--- a/plugins/kotlin/testData/results/pkg/TestTopLevelKt.dec
+++ b/plugins/kotlin/testData/results/pkg/TestTopLevelKt.dec
@@ -5,7 +5,7 @@ public final val topLevelVal: Regex = new Regex("")
 public final var topLevelVar: Int = 42
    internal set
 
-fun topLevelFun() {
+public fun topLevelFun() {
 }// 5
 
 
diff --git a/plugins/kotlin/testData/results/pkg/TestTryCatchExpressions.dec b/plugins/kotlin/testData/results/pkg/TestTryCatchExpressions.dec
index 11071ce530..53bf0f58a2 100644
--- a/plugins/kotlin/testData/results/pkg/TestTryCatchExpressions.dec
+++ b/plugins/kotlin/testData/results/pkg/TestTryCatchExpressions.dec
@@ -3,12 +3,12 @@ package pkg
 import java.io.IOException
 
 class TestTryCatchExpressions {
-   fun test0(s: String) {
-      var var2: String;
+   public fun test0(s: String) {
+      var var2: java.lang.String;
       try {
-         var2 = StringsKt.repeat(s as CharSequence, 5);// 9
+         var2 = StringsKt.repeat(s as java.lang.CharSequence, 5);// 9
       } catch (RuntimeException var4) {// 10
-         var var10000: String = var4.getMessage();// 11
+         var var10000: java.lang.String = var4.getMessage();// 11
          if (var10000 == null) {
             var10000 = "ERROR";
          }
@@ -19,19 +19,19 @@ class TestTryCatchExpressions {
       System.out.print(var2);// 7
    }// 14
 
-   fun test1(a: String, b: String) {
-      var x: String = a;// 17
+   public fun test1(a: String, b: String) {
+      var x: java.lang.String = a;// 17
       var var6: TestTryCatchExpressions = this;// 19
 
-      var var4: String;
+      var var4: java.lang.String;
       var var10000: TestTryCatchExpressions;
       try {
          var10000 = var6;
-         var4 = StringsKt.repeat(x as CharSequence, 5);// 20
+         var4 = StringsKt.repeat(x as java.lang.CharSequence, 5);// 20
       } catch (RuntimeException var9) {// 21
          var10000 = this;
          x = b;// 22
-         var var10001: String = var9.getMessage();// 23
+         var var10001: java.lang.String = var9.getMessage();// 23
          if (var10001 == null) {
             var10001 = "ERROR";
          }
@@ -39,18 +39,18 @@ class TestTryCatchExpressions {
          var4 = var10001;
       }
 
-      var var7: String = var4;// 24
+      var var7: java.lang.String = var4;// 24
       var6 = var10000;
 
-      var var13: String;
+      var var13: java.lang.String;
       try {
          var10000 = var6;
          var13 = var7;
-         var4 = StringsKt.repeat(x as CharSequence, 5);// 25
+         var4 = StringsKt.repeat(x as java.lang.CharSequence, 5);// 25
       } catch (RuntimeException var8) {// 26
          var10000 = var10000;
          var13 = var4;
-         var var10002: String = var8.getMessage();// 27
+         var var10002: java.lang.String = var8.getMessage();// 27
          if (var10002 == null) {
             var10002 = "ERROR";
          }
@@ -61,11 +61,11 @@ class TestTryCatchExpressions {
       var10000.test0(var13 + var4);// 18
    }// 30
 
-   fun test2(a: String, b: String) {
-      var var15: Any = a;// 33
+   public fun test2(a: String, b: String) {
+      var var15: java.lang.String = a;// 33
       var var7: TestTryCatchExpressions = this;
 
-      var var4: String;
+      var var4: java.lang.String;
       var var10000: TestTryCatchExpressions;
       try {
          var10000 = var7;
@@ -87,12 +87,12 @@ class TestTryCatchExpressions {
          var4 = var15;// 51
       }
 
-      var var8: String = var4;// 52
+      var var8: java.lang.String = var4;// 52
       var7 = var10000;
 
-      var var10001: String;
+      var var10001: java.lang.String;
       try {
-         var4 = StringsKt.repeat(var15 as CharSequence, 5);
+         var4 = StringsKt.repeat(var15 as java.lang.CharSequence, 5);
          var15 = var4;
          var10000 = var7;
          var10001 = var8;
@@ -101,7 +101,7 @@ class TestTryCatchExpressions {
          var10000 = var10000;
          var10001 = var4;
          System.out.println(var15);// 55
-         var var10003: String = var12.getMessage();
+         var var10003: java.lang.String = var12.getMessage();
          if (var10003 == null) {
             var10003 = "";
          }
diff --git a/plugins/kotlin/testData/results/pkg/TestTryFinallyExpressions.dec b/plugins/kotlin/testData/results/pkg/TestTryFinallyExpressions.dec
index c06ead4362..f90533dff6 100644
--- a/plugins/kotlin/testData/results/pkg/TestTryFinallyExpressions.dec
+++ b/plugins/kotlin/testData/results/pkg/TestTryFinallyExpressions.dec
@@ -3,11 +3,11 @@ package pkg
 import java.io.IOException
 
 class TestTryFinallyExpressions {
-   fun test0(s: String) {
+   public fun test0(s: String) {
       label15: {
          try {
-            var var2: String = StringsKt.repeat(s as CharSequence, 5);// 8
-         } catch (Throwable var4) {
+            var var2: java.lang.String = StringsKt.repeat(s as java.lang.CharSequence, 5);// 8
+         } catch (java.lang.Throwable var4) {
             System.out.println("bye");// 10
          }
 
@@ -15,21 +15,21 @@ class TestTryFinallyExpressions {
       }
    }
 
-   fun test1(a: String, b: String) {
+   public fun test1(a: String, b: String) {
       label24: {
-         var x: String = a;// 15
+         var x: java.lang.String = a;// 15
 
          try {
-            var var4: String = StringsKt.repeat(x as CharSequence, 5);// 17
-         } catch (Throwable var9) {
+            var var4: java.lang.String = StringsKt.repeat(x as java.lang.CharSequence, 5);// 17
+         } catch (java.lang.Throwable var9) {
             ;
          }
 
          x = b;// 18 19 20
 
          try {
-            var var15: String = StringsKt.repeat(x as CharSequence, 5);// 21
-         } catch (Throwable var8) {
+            var var15: java.lang.String = StringsKt.repeat(x as java.lang.CharSequence, 5);// 21
+         } catch (java.lang.Throwable var8) {
             System.out.println(a);// 23
          }
 
@@ -37,9 +37,9 @@ class TestTryFinallyExpressions {
       }
    }
 
-   fun test2(a: String, b: String) {
+   public fun test2(a: String, b: String) {
       label68: {
-         var var19: Any = a;// 28
+         var var19: java.lang.String = a;// 28
 
          label69: {
             label70: {
@@ -56,9 +56,9 @@ class TestTryFinallyExpressions {
                      } catch (IOException var11) {// 36
                         var19 = a;// 37
                         this.test1(a, a);// 38
-                        var var4: String = a;// 39
+                        var var4: java.lang.String = a;// 39
                      }
-                  } catch (Throwable var12) {
+                  } catch (java.lang.Throwable var12) {
                      var19 = if (var19 == a) b else a;// 41 42 44
                   }
 
@@ -70,8 +70,8 @@ class TestTryFinallyExpressions {
             }
 
             try {
-               var19 = StringsKt.repeat(var19 as CharSequence, 5);// 47
-            } catch (Throwable var10) {
+               var19 = StringsKt.repeat(var19 as java.lang.CharSequence, 5);// 47
+            } catch (java.lang.Throwable var10) {
                System.out.println(var19);// 49
             }
 
diff --git a/plugins/kotlin/testData/results/pkg/TestVars.dec b/plugins/kotlin/testData/results/pkg/TestVars.dec
index 20576f4fea..e2eb7f5894 100644
--- a/plugins/kotlin/testData/results/pkg/TestVars.dec
+++ b/plugins/kotlin/testData/results/pkg/TestVars.dec
@@ -1,15 +1,15 @@
 package pkg
 
 class TestVars {
-   fun testVar() {
+   public fun testVar() {
       System.out.println("initial");// 5 6
    }// 9
 
-   fun testVal() {
+   public fun testVal() {
       System.out.println("initial");// 12 13
    }// 16
 
-   fun testPhi(bl: Boolean) {
+   public fun testPhi(bl: Boolean) {
       var var3: Byte;
       if (bl) {// 21
          var3 = 1;// 22
@@ -20,7 +20,7 @@ class TestVars {
       System.out.println(var3);// 27
    }// 28
 
-   fun testIfExpr(bl: Boolean) {
+   public fun testIfExpr(bl: Boolean) {
       System.out.println(if (bl) 1 else 2);// 31 32 34 37
    }// 38
 }
diff --git a/plugins/kotlin/testData/results/pkg/TestWhen.dec b/plugins/kotlin/testData/results/pkg/TestWhen.dec
index 76d811f80d..a29a8ffc73 100644
--- a/plugins/kotlin/testData/results/pkg/TestWhen.dec
+++ b/plugins/kotlin/testData/results/pkg/TestWhen.dec
@@ -1,34 +1,34 @@
 package pkg
 
 class TestWhen {
-   fun testStatement(obj: Any) {
+   public fun testStatement(obj: Any) {
       if (obj == 1) {// 5 6
          System.out.println("1");
       } else if (obj == "2") {// 7
          System.out.println("2");
-      } else if (obj is Double) {// 8
+      } else if (obj is java.lang.Double) {// 8
          System.out.println("Double");
-      } else if (obj !is Long) {// 9
+      } else if (obj !is java.lang.Long) {// 9
          System.out.println("Not Long");
       } else {
          System.out.println("else");// 10
       }
    }// 12
 
-   fun testExpression(obj: Any): Int {
-      return if (obj == 1) 1 else (if (obj is Double) 2 else (if (obj == "4") 4 else (if (obj !is Long) 3 else 5)));// 15 16 17 18 19 20
+   public fun testExpression(obj: Any): Int {
+      return if (obj == 1) 1 else (if (obj is java.lang.Double) 2 else (if (obj == "4") 4 else (if (obj !is java.lang.Long) 3 else 5)));// 15 16 17 18 19 20
    }
 
-   fun testStatement2(a: Any, b: Any) {
+   public fun testStatement2(a: Any, b: Any) {
       if (a == 15) {// 26
          System.out.println("a == 15");
       } else if (a == "!!") {// 27
          System.out.println("a == !!");
       } else if (a is Integer) {// 28
          System.out.println("a is Int");
-      } else if (a is String) {// 29
+      } else if (a is java.lang.String) {// 29
          System.out.println("a is String");
-      } else if (b is Double) {// 30
+      } else if (b is java.lang.Double) {// 30
          System.out.println("b is Double");
       } else if (a is Unit) {// 31
          System.out.println("a is Unit");
@@ -37,7 +37,7 @@ class TestWhen {
       }
    }// 34
 
-   fun booleanNightmares(a: Boolean, b: Boolean, c: Boolean, d: Boolean, e: Boolean, f: Boolean, g: Boolean) {
+   public fun booleanNightmares(a: Boolean, b: Boolean, c: Boolean, d: Boolean, e: Boolean, f: Boolean, g: Boolean) {
       if (a == (b != c)) {// 37 38
          System.out.println("-_-");
       } else if (a == (b && !e)) {// 39
diff --git a/plugins/kotlin/testData/results/pkg/TestWhenBoolean.dec b/plugins/kotlin/testData/results/pkg/TestWhenBoolean.dec
index fddb00ed10..e288eca3d1 100644
--- a/plugins/kotlin/testData/results/pkg/TestWhenBoolean.dec
+++ b/plugins/kotlin/testData/results/pkg/TestWhenBoolean.dec
@@ -1,7 +1,7 @@
 package pkg
 
 class TestWhenBoolean {
-   fun testIf(a: Int, b: Int, c: Int, d: Int) {
+   public fun testIf(a: Int, b: Int, c: Int, d: Int) {
       if (a == 1// 6 18
          || b == 2// 7
          || c != 3// 8
diff --git a/plugins/kotlin/testData/results/pkg/TestWhenControlFlow.dec b/plugins/kotlin/testData/results/pkg/TestWhenControlFlow.dec
index 40d0b29a8d..850f632e23 100644
--- a/plugins/kotlin/testData/results/pkg/TestWhenControlFlow.dec
+++ b/plugins/kotlin/testData/results/pkg/TestWhenControlFlow.dec
@@ -1,7 +1,7 @@
 package pkg
 
 class TestWhenControlFlow {
-   fun test1(x: Int) {
+   public fun test1(x: Int) {
       var xx: Int = x;// 5
 
       while (xx > 0) {// 7
diff --git a/plugins/kotlin/testData/src/kt/pkg/TestContracts.kt b/plugins/kotlin/testData/src/kt/pkg/TestContracts.kt
new file mode 100644
index 0000000000..70b75e4084
--- /dev/null
+++ b/plugins/kotlin/testData/src/kt/pkg/TestContracts.kt
@@ -0,0 +1,55 @@
+package pkg
+
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
+
+@OptIn(ExperimentalContracts::class)
+class TestContracts {
+  fun testSimpleContract(x: Int?): Int {
+    contract {
+      returns() implies (x != null)
+    }
+    if (x == null) error("x is null")
+    return x
+  }
+
+  fun testBooleanContract(a: Boolean, b: Boolean): Boolean? {
+    contract {
+      returns(true) implies (!a && !b)
+      returns(null) implies (a && b)
+      returns(false) implies ((a && !b) || (!a && b))
+    }
+
+    return if (a && b) null else a || b
+  }
+
+  fun testTypeContract(x: Any?): Int {
+    contract {
+      returns() implies (x is Int)
+    }
+    if (x !is Int) error("x is not Int")
+    return x
+  }
+
+  fun testFunctionalContract(f: () -> Int): Int {
+    contract {
+      callsInPlace(f, InvocationKind.EXACTLY_ONCE)
+    }
+    return f()
+  }
+
+  fun testFunctionalContract2(f: () -> Int, b: Boolean): Int {
+    contract {
+      callsInPlace(f, InvocationKind.AT_MOST_ONCE)
+    }
+    return if (b) f() else 0
+  }
+
+  fun testFunctionalContract3(f: () -> Int, i: Int): Int {
+    contract {
+      callsInPlace(f)
+    }
+    return (0..i).sumOf { f() }
+  }
+}
diff --git a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java
index 9ebc8e85a3..70a5fe4ce4 100644
--- a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java
+++ b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java
@@ -96,6 +96,10 @@ public static void startMethod(VarProcessor varProcessor) {
     context.counterContainer = new CounterContainer();
   }
 
+  public static void setImportCollector(ImportCollector importCollector) {
+    getCurrentContext().importCollector = importCollector;
+  }
+
   // *****************************************************************************
   // context access
   // *****************************************************************************
diff --git a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
index 8f0dd8013a..e681ace76d 100644
--- a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
+++ b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
@@ -18,14 +18,14 @@
 public class ImportCollector {
   private static final String JAVA_LANG_PACKAGE = "java.lang";
 
-  private final Map<String, String> mapSimpleNames = new HashMap<>();
-  private final Set<String> setNotImportedNames = new HashSet<>();
+  protected final Map<String, String> mapSimpleNames = new HashMap<>();
+  protected final Set<String> setNotImportedNames = new HashSet<>();
   // set of field names in this class and all its predecessors.
-  private final Set<String> setFieldNames = new HashSet<>();
-  private final Map<String, Map<String, String>> mapInnerClassNames = new HashMap<>();
-  private final String currentPackageSlash;
-  private final String currentPackagePoint;
-  private boolean writeLocked = false;
+  protected final Set<String> setFieldNames = new HashSet<>();
+  protected final Map<String, Map<String, String>> mapInnerClassNames = new HashMap<>();
+  protected final String currentPackageSlash;
+  protected final String currentPackagePoint;
+  protected boolean writeLocked = false;
 
   public ImportCollector(ClassNode root) {
     String clName = root.classStruct.qualifiedName;
@@ -64,6 +64,16 @@ public ImportCollector(ClassNode root) {
 
     collectConflictingShortNames(root, new HashMap<>());
   }
+  
+  public ImportCollector(ImportCollector other) {
+    this.mapSimpleNames.putAll(other.mapSimpleNames);
+    this.setNotImportedNames.addAll(other.setNotImportedNames);
+    this.setFieldNames.addAll(other.setFieldNames);
+    this.mapInnerClassNames.putAll(other.mapInnerClassNames);
+    this.currentPackageSlash = other.currentPackageSlash;
+    this.currentPackagePoint = other.currentPackagePoint;
+    this.writeLocked = other.writeLocked;
+  }
 
   /**
    * Check whether the package-less name ClassName is shaded by variable in a context of
@@ -190,21 +200,27 @@ public void writeImports(TextBuffer buffer, boolean addSeparator) {
     }
   }
 
-  private List<String> packImports() {
+  protected List<String> packImports() {
     return mapSimpleNames.entrySet().stream()
-      .filter(ent ->
-                // exclude the current class or one of the nested ones
-                // empty, java.lang and the current packages
-                !setNotImportedNames.contains(ent.getKey()) &&
-                !ent.getValue().isEmpty() &&
-                !JAVA_LANG_PACKAGE.equals(ent.getValue()) &&
-                !ent.getValue().equals(currentPackagePoint)
-      )
+      .filter(this::keepImport)
       .sorted(Map.Entry.<String, String>comparingByValue().thenComparing(Map.Entry.comparingByKey()))
       .map(ent -> ent.getValue() + "." + ent.getKey())
       .collect(Collectors.toList());
   }
 
+  /**
+   * Check whether to keep the given entry in the import list.
+   *
+   * @param ent the entry in the map containing the class name and its corresponding package name
+   * @return true if the entry should be kept for importing, false otherwise
+   */
+  protected boolean keepImport(Map.Entry<String, String> ent) {
+    return !setNotImportedNames.contains(ent.getKey()) &&
+           !ent.getValue().isEmpty() &&
+           !JAVA_LANG_PACKAGE.equals(ent.getValue()) &&
+           !ent.getValue().equals(currentPackagePoint);
+  }
+
   private void collectConflictingShortNames(ClassNode root, Map<String, String> rootNames) {
     Map<String, String> names = new HashMap<>(rootNames);
     getSuperClassInnerClasses(root, names);