K2 컴파일러는 Kotlin 2.0.0부터 기본적으로 활성화된다.
Kotlin 2.0.0에서의 K2 컴파일러는 이전보다 더 많은 시나리오에서 스마트 캐스팅을 수행한다.
if 문 내에서 non-null 임을 알았다면 if 조건문 내부의 지역변수는 스마트 캐스팅 되었다. (nullable → non-null)non-null임을 확인해도 스마트 캐스팅할 수 없었다. (when이나 while 구문도 마찬가지)class Cat {
fun purr() {
println("Purr purr")
}
}
fun petAnimal(animal: Any) {
val isCat = animal is Cat
if (isCat) {
// Kotlin 2.0.0에선 컴파일러가 isCat에 접근할 수 있기에
// animal을 스마트 캐스팅할 수 있다.
// 때문에 purr() 메서드를 호출할 수 있는 것
animal.purr() // smart casting!
}
}
fun main(){
val kitty = Cat()
petAnimal(kitty)
// Purr purr
}
||)로 수행하면 가장 가까운 공통 상위 유형으로 스마트 캐스팅을 수행한다.
Any 유형으로 캐스팅 되었음interface Status {
fun signal() {}
}
interface Ok : Status
interface Postponed : Status
interface Declined : Status
fun signalCheck(signalStatus: Any) {
if (signalStatus is Postponed || signalStatus is Declined) {
// signalStatus 변수가 두 타입의 공통 상위 타입인 Status로 캐스팅된다.
signalStatus.signal() // signal()을 호출할 수 있게 된다.
}
}
interface Processor {
fun process()
}
inline fun inlineAction(f: () -> Unit) = f()
fun nextProcessor(): Processor? = null
fun runProcessor(): Processor? {
var processor: Processor? = null
inlineAction {
// Kotlin 2.0.0에선 컴파일러가 processor가 지역 변수이고 inlineAction이
// 인라인 함수임을 알기에 processor가 유출될 수 없음을 안다.
// 그러므로 processor로 스마트 캐스트하는 것이 안전하다.
if (processor != null) {
// null이 아님을 알았다면 safe-call을 할 필요 없이
// 스마트 캐스팅 되어 함수를 호출할 수 있다.
processor.process()
// 이전에는 processor?.process()로 사용해야 했다.
}
processor = nextProcessor()
}
return processor
}
class Holder(val provider: (() -> Unit)?) {
fun process() {
if (provider != null) {
// 컴파일러가 provider가 null이 아님을 안다.
provider()
// 이전 버전에서는 safe-call을 해야 했다.
}
}
}
catch 및 finally 블록에 전달할 수 있도록 했다.fun testString() {
var stringInput: String? = null
// 값을 할당함으로써 non-null String 타입으로 스마트 캐스팅
stringInput = ""
try {
// 컴파일러는 null이 아님을 안다.
println(stringInput.length)
// 0
// 컴파일러는 다시 String? 타입으로 인식
stringInput = null
// 예외를 발생시키기
if (2 > 1) throw Exception()
stringInput = ""
} catch (exception: Exception) {
// Kotlin 2.0.0에서 stringInput이 nullable임을 알아서 safe-call 수행
println(stringInput?.length)
// null
// Kotlin 1.9.20에선 safe-call이 필요하지 않다고 말할 것이다.
}
}
interface Rho {
operator fun inc(): Sigma = TODO()
}
interface Sigma : Rho {
fun sigma() = Unit
}
interface Tau {
fun tau() = Unit
}
fun main(input: Rho) {
var unknownObject: Rho = input
// unknownObject는 Rho와 Tau 타입이 모두 될 수 있다.
if (unknownObject is Tau) {
// Rho 타입으로써 inc 증가 연산자를 호출
// Kotlin 2.0.0에선 Sigma 타입으로 스마트 캐스팅 된다.
++unknownObject
// 때문에 Sigma 타입의 sigma() 함수를 성공적으로 호출한다.
unknownObject.sigma()
// In Kotlin 2.0.0에선 컴파일러기 unknownObjet를 Sigma 타입이라
// 알고 있기에 아래 구문은 컴파일 에러가 발생한다.
unknownObject.tau()
// In Kotlin 1.9.20에선 컴파일 에러가 발생하지 않고 런타임에
// ClassCastException이 발생한다.
}
}
K2 컴파일러에는 다음과 같은 영역에서 Kotlin 멀티플랫폼 관련 개선 사항이 있다.
// Commmon code
fun foo(x: Any) = println("common foo")
fun exampleFunction() {
foo(42)
}
// Platform code
// JVM
fun foo(x: Int) = println("platform foo")
// JavaScript
// 자바스크립트 플랫폼에는 foo() 함수 오버로드가 없다.
foo를 호출하면 플랫폼 코드의 foo가 호출된다. (platform foo 출력)를 호출하면 플랫폼 코드엔 해당 함수가 없어 공통 코드의 foo가 호출된다. (common foo 출력)Kotlin 2.0.0에선 공통 코드가 플랫폼 코드에 엑세스할 수 없기 때문에 두 플랫폼 모두 공통 코드의 foo 함수를 호출한다. (common foo 출력)
expect internal class Attribute // internal
actual class Attribute // public
https://kotlinlang.org/docs/k2-compiler-migration-guide.html