[IR] More user-friendly compilation exceptions from lowerings and JS codegen
Merge-request: KT-MR-5004
This commit is contained in:
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.path
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.dumpKotlinLike
|
||||
import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||
|
||||
class CompilationException(
|
||||
message: String,
|
||||
// file is not known in any moment, need to set it later in catch to save stacktrace
|
||||
var file: IrFile?,
|
||||
val ir: Any?, /* IrElement | IrType */
|
||||
cause: Throwable? = null
|
||||
) : RuntimeException(message, cause) {
|
||||
override val message: String
|
||||
get() = buildString {
|
||||
appendLine("Back-end: Please report this problem https://kotl.in/issue")
|
||||
path?.let { appendLine("$it:$line:$column") }
|
||||
content?.let { appendLine("Problem with `$it`") }
|
||||
append("Details: " + super.message)
|
||||
}
|
||||
|
||||
val line: Int
|
||||
get() {
|
||||
val irStartOffset = irStartOffset
|
||||
?: return UNDEFINED_OFFSET
|
||||
|
||||
val lineNumber = file?.fileEntry?.getLineNumber(irStartOffset)
|
||||
?: return UNDEFINED_OFFSET
|
||||
|
||||
return lineNumber + 1
|
||||
}
|
||||
|
||||
val column: Int
|
||||
get() {
|
||||
val irStartOffset = irStartOffset
|
||||
?: return UNDEFINED_OFFSET
|
||||
|
||||
val columnNumber = file?.fileEntry?.getColumnNumber(irStartOffset)
|
||||
?: return UNDEFINED_OFFSET
|
||||
|
||||
return columnNumber + 1
|
||||
}
|
||||
|
||||
private val irStartOffset: Int?
|
||||
get() = (ir as? IrElement)?.startOffset
|
||||
|
||||
val path: String?
|
||||
get() = file?.path
|
||||
|
||||
val content: String?
|
||||
get() = when (ir) {
|
||||
is IrElement -> ir.dumpKotlinLike()
|
||||
is IrType -> ir.dumpKotlinLike()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun compilationException(message: String, element: IrElement): Nothing {
|
||||
throw CompilationException(message, null, element)
|
||||
}
|
||||
|
||||
fun compilationException(message: String, type: IrType?): Nothing {
|
||||
throw CompilationException(message, null, type)
|
||||
}
|
||||
|
||||
fun compilationException(message: String, declaration: IrDeclaration): Nothing {
|
||||
val file = try {
|
||||
declaration.fileOrNull
|
||||
} catch (e: Throwable) {
|
||||
null
|
||||
}
|
||||
throw CompilationException(message, file, declaration)
|
||||
}
|
||||
|
||||
fun Throwable.wrapWithCompilationException(
|
||||
message: String,
|
||||
file: IrFile,
|
||||
element: IrElement?
|
||||
): CompilationException {
|
||||
return CompilationException(
|
||||
"$message: ${this::class.qualifiedName}: ${this.message}",
|
||||
file,
|
||||
element,
|
||||
cause = this
|
||||
).apply {
|
||||
stackTrace = this@wrapWithCompilationException.stackTrace
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,22 @@ interface BodyAndScriptBodyLoweringPass : BodyLoweringPass {
|
||||
override fun lower(irFile: IrFile) = runOnFilePostfix(irFile)
|
||||
}
|
||||
|
||||
fun FileLoweringPass.lower(moduleFragment: IrModuleFragment) = moduleFragment.files.forEach { lower(it) }
|
||||
fun FileLoweringPass.lower(
|
||||
moduleFragment: IrModuleFragment
|
||||
) = moduleFragment.files.forEach {
|
||||
try {
|
||||
lower(it)
|
||||
} catch (e: CompilationException) {
|
||||
e.file = it
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
throw e.wrapWithCompilationException(
|
||||
"Internal error in file lowering",
|
||||
it,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun ClassLoweringPass.runOnFilePostfix(irFile: IrFile) {
|
||||
irFile.acceptVoid(ClassLoweringVisitor(this))
|
||||
@@ -128,7 +143,18 @@ fun BodyLoweringPass.runOnFilePostfix(
|
||||
) {
|
||||
val visitor = BodyLoweringVisitor(this, withLocalDeclarations, allowDeclarationModification)
|
||||
for (declaration in ArrayList(irFile.declarations)) {
|
||||
declaration.accept(visitor, null)
|
||||
try {
|
||||
declaration.accept(visitor, null)
|
||||
} catch (e: CompilationException) {
|
||||
e.file = irFile
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
throw e.wrapWithCompilationException(
|
||||
"Internal error in body lowering",
|
||||
irFile,
|
||||
declaration
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,8 +240,19 @@ interface DeclarationTransformer : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
val visitor = Visitor(this)
|
||||
irFile.declarations.transformFlat { declaration ->
|
||||
declaration.acceptVoid(visitor)
|
||||
transformFlatRestricted(declaration)
|
||||
try {
|
||||
declaration.acceptVoid(visitor)
|
||||
transformFlatRestricted(declaration)
|
||||
} catch (e: CompilationException) {
|
||||
e.file = irFile
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
throw e.wrapWithCompilationException(
|
||||
"Internal error in declaration transformer",
|
||||
irFile,
|
||||
declaration
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user