JVM IR: Validate corresponding properties

This commit is contained in:
Steven Schäfer
2020-04-20 17:30:14 +02:00
committed by Alexander Udalov
parent 13f15a702b
commit 9bc8fdcb3c
5 changed files with 24 additions and 13 deletions
@@ -76,6 +76,19 @@ class CheckIrElementVisitor(
} }
} }
private fun IrElement.checkFunction(function: IrFunction) {
if (function is IrSimpleFunction && config.checkProperties) {
val property = function.correspondingPropertySymbol?.owner
if (property != null && property.getter != function && property.setter != function) {
reportError(this, "Orphaned property getter/setter ${function.render()}")
}
}
if (function.dispatchReceiverParameter?.type is IrDynamicType) {
reportError(this, "Dispatch receivers with 'dynamic' type are not allowed")
}
}
override fun <T> visitConst(expression: IrConst<T>) { override fun <T> visitConst(expression: IrConst<T>) {
super.visitConst(expression) super.visitConst(expression)
@@ -152,10 +165,8 @@ class CheckIrElementVisitor(
super.visitCall(expression) super.visitCall(expression)
val function = expression.symbol.owner val function = expression.symbol.owner
expression.checkFunction(function)
if (function.dispatchReceiverParameter?.type is IrDynamicType) {
reportError(expression, "Dispatch receivers with 'dynamic' type are not allowed")
}
// TODO: Why don't we check parameters as well? // TODO: Why don't we check parameters as well?
val returnType = expression.symbol.owner.returnType val returnType = expression.symbol.owner.returnType
@@ -267,10 +278,7 @@ class CheckIrElementVisitor(
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration) super.visitFunction(declaration)
declaration.checkFunction(declaration)
if (declaration.dispatchReceiverParameter?.type is IrDynamicType) {
reportError(declaration, "Dispatch receivers with 'dynamic' type are not allowed")
}
for ((i, p) in declaration.valueParameters.withIndex()) { for ((i, p) in declaration.valueParameters.withIndex()) {
if (p.index != i) { if (p.index != i) {
@@ -323,7 +331,7 @@ class CheckIrElementVisitor(
override fun visitFunctionReference(expression: IrFunctionReference) { override fun visitFunctionReference(expression: IrFunctionReference) {
super.visitFunctionReference(expression) super.visitFunctionReference(expression)
expression.checkFunction(expression.symbol.owner)
expression.symbol.ensureBound(expression) expression.symbol.ensureBound(expression)
} }
@@ -53,7 +53,8 @@ data class IrValidatorConfig(
val abortOnError: Boolean, val abortOnError: Boolean,
val ensureAllNodesAreDifferent: Boolean, val ensureAllNodesAreDifferent: Boolean,
val checkTypes: Boolean = true, val checkTypes: Boolean = true,
val checkDescriptors: Boolean = true val checkDescriptors: Boolean = true,
val checkProperties: Boolean = false,
) )
class IrValidator(val context: CommonBackendContext, val config: IrValidatorConfig) : IrElementVisitorVoid { class IrValidator(val context: CommonBackendContext, val config: IrValidatorConfig) : IrElementVisitorVoid {
@@ -123,12 +123,13 @@ fun <Data, Context> dumpToStdout(
val defaultDumper = makeDumpAction(dumpToStdout(::dumpIrElement) + dumpToFile("ir", ::dumpIrElement)) val defaultDumper = makeDumpAction(dumpToStdout(::dumpIrElement) + dumpToFile("ir", ::dumpIrElement))
fun <Fragment : IrElement> validationCallback(context: CommonBackendContext, fragment: Fragment) { fun <Fragment : IrElement> validationCallback(context: CommonBackendContext, fragment: Fragment, checkProperties: Boolean = false) {
val validatorConfig = IrValidatorConfig( val validatorConfig = IrValidatorConfig(
abortOnError = true, abortOnError = true,
ensureAllNodesAreDifferent = true, ensureAllNodesAreDifferent = true,
checkTypes = false, checkTypes = false,
checkDescriptors = false checkDescriptors = false,
checkProperties = checkProperties,
) )
fragment.accept(IrValidator(context, validatorConfig), null) fragment.accept(IrValidator(context, validatorConfig), null)
fragment.accept(CheckDeclarationParentsVisitor, null) fragment.accept(CheckDeclarationParentsVisitor, null)
@@ -46,13 +46,13 @@ private fun makePatchParentsPhase(number: Int) = namedIrFilePhase(
) )
private val validateIrBeforeLowering = makeCustomPhase<JvmBackendContext, IrModuleFragment>( private val validateIrBeforeLowering = makeCustomPhase<JvmBackendContext, IrModuleFragment>(
{ context, module -> validationCallback(context, module) }, { context, module -> validationCallback(context, module, checkProperties = true) },
name = "ValidateIrBeforeLowering", name = "ValidateIrBeforeLowering",
description = "Validate IR before lowering" description = "Validate IR before lowering"
) )
private val validateIrAfterLowering = makeCustomPhase<JvmBackendContext, IrModuleFragment>( private val validateIrAfterLowering = makeCustomPhase<JvmBackendContext, IrModuleFragment>(
{ context, module -> validationCallback(context, module) }, { context, module -> validationCallback(context, module, checkProperties = true) },
name = "ValidateIrAfterLowering", name = "ValidateIrAfterLowering",
description = "Validate IR after lowering" description = "Validate IR after lowering"
) )
@@ -255,6 +255,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
currentScope?.scope?.scopeOwnerSymbol ?: irClass.symbol, expression.startOffset, expression.endOffset currentScope?.scope?.scopeOwnerSymbol ?: irClass.symbol, expression.startOffset, expression.endOffset
) )
.irBlock { .irBlock {
// TODO: Move this to the enclosing class, right now the parent field is wrong!
+referenceClass +referenceClass
+irCall(referenceClass.constructors.single()).apply { +irCall(referenceClass.constructors.single()).apply {
var index = 0 var index = 0