diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/GlobalInlineContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/GlobalInlineContext.kt
index 3b155165690..5f8c1eb7ed8 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/GlobalInlineContext.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/GlobalInlineContext.kt
@@ -5,17 +5,14 @@
package org.jetbrains.kotlin.codegen.inline
-import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
-import org.jetbrains.kotlin.diagnostics.DiagnosticSink
-import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.utils.threadLocal
import java.util.*
-class GlobalInlineContext(private val diagnostics: DiagnosticSink) {
+class GlobalInlineContext {
// Ordered set of declarations and inline calls being generated right now.
// No call in it should point to a declaration that's before it in the stack.
- private val inlineCallsAndDeclarations by threadLocal { LinkedList() }
+ private val inlineCallsAndDeclarations by threadLocal { LinkedList() }
private val inlineDeclarationSet by threadLocal { mutableSetOf() }
private val typesUsedInInlineFunctions by threadLocal { LinkedList>() }
@@ -30,13 +27,17 @@ class GlobalInlineContext(private val diagnostics: DiagnosticSink) {
inlineDeclarationSet.remove(inlineCallsAndDeclarations.removeLast())
}
- fun enterIntoInlining(callee: CallableDescriptor?, element: PsiElement?): Boolean {
+ fun enterIntoInlining(
+ callee: CallableDescriptor?,
+ element: InlineFunctionSource?,
+ reportInlineCallCycle: (InlineFunctionSource, CallableDescriptor) -> Unit,
+ ): Boolean {
if (callee != null && callee.original in inlineDeclarationSet) {
- element?.let { diagnostics.report(Errors.INLINE_CALL_CYCLE.on(it, callee.original)) }
+ element?.let { reportInlineCallCycle(it, callee.original) }
for ((call, callTarget) in inlineCallsAndDeclarations.dropWhile { it != callee.original }.zipWithNext()) {
// Every call element should be followed by the callee's descriptor.
- if (call is PsiElement && callTarget is CallableDescriptor) {
- diagnostics.report(Errors.INLINE_CALL_CYCLE.on(call, callTarget))
+ if (call is InlineFunctionSource && callTarget is CallableDescriptor) {
+ reportInlineCallCycle(call, callTarget)
}
}
return false
@@ -55,4 +56,6 @@ class GlobalInlineContext(private val diagnostics: DiagnosticSink) {
fun recordTypeFromInlineFunction(type: String) = typesUsedInInlineFunctions.peek().add(type)
fun isTypeFromInlineFunction(type: String) = typesUsedInInlineFunctions.peek().contains(type)
-}
\ No newline at end of file
+
+ abstract class InlineFunctionSource
+}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt
index 5936df6a5e2..158e8386660 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen.inline
+import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure
@@ -12,6 +13,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
@@ -58,8 +60,12 @@ class PsiInlineCodegen(
) {
(sourceCompiler as PsiSourceCompilerForInline).callDefault = callDefault
assert(hiddenParameters.isEmpty()) { "putHiddenParamsIntoLocals() should be called after processHiddenParameters()" }
- if (!state.globalInlineContext.enterIntoInlining(functionDescriptor, resolvedCall?.call?.callElement)) {
- generateStub(resolvedCall?.call?.callElement?.text ?: "", codegen)
+ val psiElement = resolvedCall?.call?.callElement
+ val element = psiElement?.let(::PsiInlineFunctionSource)
+ if (!state.globalInlineContext.enterIntoInlining(functionDescriptor, element) { reportOn, callee ->
+ state.diagnostics.report(Errors.INLINE_CALL_CYCLE.on((reportOn as PsiInlineFunctionSource).psi, callee))
+ }) {
+ generateStub(psiElement?.text ?: "", codegen)
return
}
try {
@@ -194,6 +200,8 @@ class PsiInlineCodegen(
val callerPackage = DescriptorUtils.getParentOfType(caller, PackageFragmentDescriptor::class.java) ?: return false
return callerPackage.fqName.asString().startsWith("kotlin.")
}
+
+ private class PsiInlineFunctionSource(val psi: PsiElement) : GlobalInlineContext.InlineFunctionSource()
}
private val FunctionDescriptor.explicitParameters
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
index 41b9fd1de3e..831e11923d4 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
@@ -255,7 +255,7 @@ class GenerationState private constructor(
IntrinsicMethods(languageVersionSettings.apiVersion <= ApiVersion.parse(KotlinVersion.CURRENT.toString())!!)
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
- val globalInlineContext: GlobalInlineContext = GlobalInlineContext(diagnostics)
+ val globalInlineContext: GlobalInlineContext = GlobalInlineContext()
val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this)
val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes(
module, languageVersionSettings, config.generateOptimizedCallableReferenceSuperClasses
diff --git a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/rendering/CommonRenderers.kt b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/rendering/CommonRenderers.kt
index 81c7104645f..707da2f7650 100644
--- a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/rendering/CommonRenderers.kt
+++ b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/rendering/CommonRenderers.kt
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.diagnostics.rendering
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
import java.io.PrintWriter
import java.io.StringWriter
@@ -18,6 +19,9 @@ object CommonRenderers {
@JvmField
val STRING = Renderer { it }
+ @JvmField
+ val NAME = Renderer { it.asString() }
+
@JvmField
val THROWABLE = Renderer {
val writer = StringWriter()
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt
index 88527e1089e..5c773dbca85 100644
--- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt
@@ -12,7 +12,9 @@ import org.jetbrains.kotlin.diagnostics.error0
import org.jetbrains.kotlin.diagnostics.error1
import org.jetbrains.kotlin.diagnostics.error2
import org.jetbrains.kotlin.diagnostics.rendering.*
+import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.NAME
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING
+import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.MemberComparator
import org.jetbrains.kotlin.utils.join
@@ -33,6 +35,8 @@ object JvmBackendErrors {
val SCRIPT_CAPTURING_ENUM by error1()
val SCRIPT_CAPTURING_ENUM_ENTRY by error1()
+ val INLINE_CALL_CYCLE by error1()
+
init {
RootDiagnosticRendererFactory.registerFactory(KtDefaultJvmErrorMessages)
}
@@ -66,5 +70,7 @@ object KtDefaultJvmErrorMessages : BaseDiagnosticRendererFactory() {
map.put(JvmBackendErrors.SCRIPT_CAPTURING_INTERFACE, "Interface {0} captures the script class instance. Try to use class instead", STRING)
map.put(JvmBackendErrors.SCRIPT_CAPTURING_ENUM, "Enum class {0} captures the script class instance. Try to use class or anonymous object instead", STRING)
map.put(JvmBackendErrors.SCRIPT_CAPTURING_ENUM_ENTRY, "Enum entry {0} captures the script class instance. Try to use class or anonymous object instead", STRING)
+
+ map.put(JvmBackendErrors.INLINE_CALL_CYCLE, "The ''{0}'' invocation is a part of inline cycle", NAME)
}
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
index 6cfb8b0b0ed..140eecfb60b 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
@@ -29,6 +29,7 @@ import java.util.*;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.*;
import static org.jetbrains.kotlin.diagnostics.rendering.Renderers.*;
+import static org.jetbrains.kotlin.diagnostics.rendering.Renderers.NAME;
import static org.jetbrains.kotlin.diagnostics.rendering.RenderingContext.of;
public class DefaultErrorMessages {
diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCallGenerator.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCallGenerator.kt
index 2b1b2dc05e3..5942c615c9c 100644
--- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCallGenerator.kt
+++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCallGenerator.kt
@@ -5,13 +5,16 @@
package org.jetbrains.kotlin.backend.jvm.codegen
-import org.jetbrains.kotlin.backend.common.psi.PsiSourceManager
+import org.jetbrains.kotlin.backend.jvm.ir.fileParent
import org.jetbrains.kotlin.backend.jvm.ir.psiElement
import org.jetbrains.kotlin.backend.jvm.ir.suspendFunctionOriginal
import org.jetbrains.kotlin.backend.jvm.mapping.IrCallableMethod
import org.jetbrains.kotlin.codegen.AsmUtil
+import org.jetbrains.kotlin.codegen.inline.GlobalInlineContext
+import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
+import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmBackendErrors
interface IrInlineCallGenerator : IrCallGenerator {
override fun genCall(
@@ -20,10 +23,12 @@ interface IrInlineCallGenerator : IrCallGenerator {
expression: IrFunctionAccessExpression,
isInsideIfCondition: Boolean,
) {
- val element = PsiSourceManager.findPsiElement(expression, codegen.irFunction)
- ?: PsiSourceManager.findPsiElement(codegen.irFunction)
+ val element = IrInlineFunctionSource(expression)
val descriptor = expression.symbol.owner.suspendFunctionOriginal().toIrBasedDescriptor()
- if (!codegen.state.globalInlineContext.enterIntoInlining(descriptor, element)) {
+ if (!codegen.state.globalInlineContext.enterIntoInlining(descriptor, element) { reportOn, callee ->
+ codegen.context.ktDiagnosticReporter.at((reportOn as IrInlineFunctionSource).ir, codegen.irFunction.fileParent)
+ .report(JvmBackendErrors.INLINE_CALL_CYCLE, callee.name)
+ }) {
genCycleStub(expression.psiElement?.text ?: "", codegen)
return
}
@@ -44,4 +49,6 @@ interface IrInlineCallGenerator : IrCallGenerator {
fun genCycleStub(text: String, codegen: ExpressionCodegen) {
AsmUtil.genThrow(codegen.visitor, "java/lang/UnsupportedOperationException", "Call is a part of inline call cycle: $text")
}
+
+ private class IrInlineFunctionSource(val ir: IrElement) : GlobalInlineContext.InlineFunctionSource()
}