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