All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.backend.jvm.lower.CheckNotNullLowering.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2019 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.jvm.lower

import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue

internal val checkNotNullPhase = makeIrFilePhase(
    ::CheckNotNullLowering,
    name = "CheckNotNullLowering",
    description = "Lower calls to the CHECK_NOT_NULL intrinsic, which are generated by psi2ir for \"!!\" expressions."
)

private class CheckNotNullLowering(private val backendContext: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
    override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()

    override fun visitCall(expression: IrCall): IrExpression {
        if (expression.symbol != backendContext.irBuiltIns.checkNotNullSymbol)
            return super.visitCall(expression)

        expression.transformChildrenVoid()
        return backendContext.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).irBlock {
            val valueArgument = expression.getValueArgument(0)!!

            // For a null-check on a variable we should not introduce a temporary, since null checks are
            // optimized by RedundantNullCheckMethodTransformer, which remembers that the argument variable
            // is non-nullable if this call succeeds.
            val argument = if (valueArgument is IrGetValue) valueArgument.symbol.owner else irTemporary(valueArgument)

            // Starting with Kotlin 1.4 null-checks are lowered to calls to the "checkNotNull" intrinsic, which
            // throws a NullPointerException on failure. Prior to Kotlin 1.4 we instead inline the null-check and
            // call the "throwNpe" intrinsic on failure which throws a KotlinNullPointerException.
            if (backendContext.state.unifiedNullChecks) {
                +irCall(backendContext.ir.symbols.checkNotNull).apply {
                    putValueArgument(0, irGet(argument))
                }
            } else {
                +irIfThen(irEqualsNull(irGet(argument)), irCall(backendContext.ir.symbols.throwNpe))
            }

            +irImplicitCast(irGet(argument), expression.type)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy