K2: report INLINE_CALL_CYCLE error in JVM backend
This fixes the following FirLightTreeDiagnosticsTestWithJvmIrBackendGenerated tests: testPropertyInlineCycle testInlineCycle testSuspendInlineCycle testIndirectInlineCycle #KT-59586
This commit is contained in:
@@ -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<Any? /* CallableDescriptor | PsiElement? */>() }
|
||||
private val inlineCallsAndDeclarations by threadLocal { LinkedList<Any? /* CallableDescriptor | InlineFunctionSource? */>() }
|
||||
private val inlineDeclarationSet by threadLocal { mutableSetOf<CallableDescriptor>() }
|
||||
|
||||
private val typesUsedInInlineFunctions by threadLocal { LinkedList<MutableSet<String>>() }
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
abstract class InlineFunctionSource
|
||||
}
|
||||
|
||||
@@ -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 ?: "<no source>", 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 ?: "<no source>", 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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user