[JVM IR] Fix issue where fields are not being set to their default

values within initializer blocks.

The issue occurs in code like this:
```
class C {
  var b = true
  init {
    b = false   // Missing PUTFIELD for this statement
  }
}
```

Added a new statement origin for field initialization (at declaration)
instead of relying on `origin == null` in ExpressionCodegen to determine
whether to generate the initializations.

This was unintentionally broken in
d68a1898d0.
This commit is contained in:
Mark Punzalan
2020-02-14 13:19:59 -08:00
committed by Dmitry Petrov
parent 56c819f06e
commit 64141b8b38
17 changed files with 464 additions and 8 deletions
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
@@ -79,7 +76,15 @@ abstract class InitializersLoweringBase(open val context: CommonBackendContext)
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol)
else
null
IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, expression, context.irBuiltIns.unitType)
IrSetFieldImpl(
startOffset,
endOffset,
declaration.symbol,
receiver,
expression,
context.irBuiltIns.unitType,
IrStatementOrigin.INITIALIZE_FIELD
)
}
private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement =
@@ -565,9 +565,7 @@ class ExpressionCodegen(
// Do not add redundant field initializers that initialize to default values.
val inPrimaryConstructor = irFunction is IrConstructor && irFunction.isPrimary
val inClassInit = irFunction.origin == JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER
// "expression.origin == null" means that the field is initialized when it is declared,
// i.e., not in an initializer block or constructor body.
val isFieldInitializer = expression.origin == null
val isFieldInitializer = expression.origin == IrStatementOrigin.INITIALIZE_FIELD
val skip = (inPrimaryConstructor || inClassInit) && isFieldInitializer && expressionValue is IrConst<*> &&
isDefaultValueForType(expression.symbol.owner.type.asmType, expressionValue.value)
return if (skip) defaultValue(expression.type) else super.visitSetField(expression, data)
@@ -91,6 +91,7 @@ interface IrStatementOrigin {
object OBJECT_LITERAL : IrStatementOriginImpl("OBJECT_LITERAL")
object INITIALIZE_PROPERTY_FROM_PARAMETER : IrStatementOriginImpl("INITIALIZE_PROPERTY_FROM_PARAMETER")
object INITIALIZE_FIELD : IrStatementOriginImpl("INITIALIZE_FIELD")
object PROPERTY_REFERENCE_FOR_DELEGATE : IrStatementOriginImpl("PROPERTY_REFERENCE_FOR_DELEGATE")