Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Compiler Plugin 맛보기

Ji Sungbin
November 09, 2024

Kotlin Compiler Plugin 맛보기

Ji Sungbin

November 09, 2024
Tweet

More Decks by Ji Sungbin

Other Decks in Technology

Transcript

  1. 후원해 주신 김성윤, 김택우 님 감사합니다! 성윤 님의 E스포츠 코칭

    서비스: is.gd/WinTracker 택우 님이 기여하신 디스코드 봇 프레임워크: github.com/harmonyland/harmony
  2. 코드 형태 분석 우리가 작성한 코드를 섬세한 토큰 단위로 분석하여,

    이 API가 올바르게 사용되었는지, 코틀린 문법상 문제는 없는지, 최적화 가능한 요소가 있는지 등, 언어의 표면적인 부분을 검사합니다. 동적 코드 변형 분석된 코드 형태를 보고 다양한 최적화를 적용하거나, 기존에는 없던 새로운 코드를
 추가합니다. 새로운 키워드 추가 (X) 아쉽게도 못하는 기능 Kotlin Compiler Plugin
  3. 코드 형태 분석 우리가 작성한 코드를 섬세한 토큰 단위로 분석하여,

    이 API가 올바르게 사용되었는지, 코틀린 문법상 문제는 없는지, 최적화 가능한 요소가 있는지 등, 언어의 표면적인 부분을 검사합니다. 동적 코드 변형 분석된 코드 형태를 보고 다양한 최적화를 적용하거나, 기존에는 없던 새로운 코드를
 추가합니다. 새로운 키워드 추가 ➔ 어노테이션 + 기존 경고 억제 어노테이션을 새로운 키워드로 취급하고, 잘못된 문법으로 발생하는 코틀린 언어적 
 경고를 억제합니다. Kotlin Compiler Plugin
  4. 성빈은 왜 배웠을까? “KSP의 단점을 극복하고 싶었다” 성빈의 경우 default

    argument를 복사하면서 코드 생성이 필요했음. KSP는 declaration 영역만 접근이 가능하기에,
 default argument와 같은 expression은 접근이 불가능함. -> default argument의 expression을 알 수 없어, 성빈이 원하는 기능을 KSP로는 구현할 수 없음 ->
  5. Intermediate Representation Source Code와 Machine Code의 중간 표현. 대부분의 컴파일러는

    IR을 사용해서 Source ⭤ Machine 간의 중복 코드/작업을 최소화한다. (하나의 IR만 관리하면 모든 Machine Code에 반영됨)
  6. IrFile 파일 정의를 의미하는 IR class ⭢ 최상위 부모 IR

    class IrFunction 함수 정의를 의미하는 IR class IrCall 함수 호출과 같은 Call Expression을 의미하는 IR class Intermediate Representation
  7. 코드 형태 분석 (= Frontend IR) 우리가 작성한 코드를 섬세한

    토큰 단위로 분석하여, 이 API가 올바르게 사용되었는지, 코틀린 문법상 문제는 없는지, 최적화 가능한 요소가 있는지 등, 언어의 표면적인 부분을 검사합니다. 동적 코드 변형 (= IR) 분석된 코드 형태를 보고 다양한 최적화를 적용하거나, 기존에는 없던 새로운 코드를
 추가합니다. 새로운 키워드 추가: 어노테이션 + 기존 경고 억제 (= FIR + IR) 어노테이션을 새로운 키워드로 취급하고, 잘못된 문법으로 발생하는 코틀린 언어적 
 경고를 억제합니다. Kotlin Compiler Plugin
  8. 코드 형태 분석 (= Frontend IR) 우리가 작성한 코드를 섬세한

    토큰 단위로 분석하여, 이 API가 올바르게 사용되었는지, 코틀린 문법상 문제는 없는지, 최적화 가능한 요소가 있는지 등, 언어의 표면적인 부분을 검사합니다. 동적 코드 변형 (= IR) 분석된 코드 형태를 보고 다양한 최적화를 적용하거나, 기존에는 없던 새로운 코드를
 추가합니다. 새로운 키워드 추가: 어노테이션 + 기존 경고 억제 (= FIR + IR) 어노테이션을 새로운 키워드로 취급하고, 잘못된 문법으로 발생하는 코틀린 언어적 
 경고를 억제합니다. Kotlin Compiler Plugin
  9. package land.sungbin.calculation

 fun plus(a: Int, b: Int) {
 println(a +

    b)
 } IrFile [IrPackageFragment] land.sungbin.calculation
  10. package fun land.sungbin.calculation

 plus(a: Int, b: Int) {
 println(a +

    b)
 } IrFile [IrPackageFragment] land.sungbin.calculation [IrFunction] name: plus
  11. package fun land.sungbin.calculation

 (a: Int ) plus , b: Int

    {
 println(a + b)
 } IrFile [IrPackageFragment] land.sungbin.calculation [IrFunction] name: plus [IrValueParameter] name: a, type: kotlin.Int
  12. package fun land.sungbin.calculation

 (a: Int, b: Int) plus {
 println(a

    + b)
 } IrFile [IrPackageFragment] land.sungbin.calculation [IrFunction] name: plus [IrValueParameter] name: a, type: kotlin.Int [IrValueParameter] name: b, type: kotlin.Int
  13. package fun land.sungbin.calculation

 (a: Int, b: Int) {
 } plus

    println(a + b)
 IrFile [IrPackageFragment] land.sungbin.calculation [IrFunction] name: plus [IrValueParameter] name: a, type: kotlin.Int [IrValueParameter] name: b, type: kotlin.Int IrBlockBody
  14. package fun land.sungbin.calculation

 (a: Int, b: Int) {
 println( )


    } plus a + b IrFile [IrPackageFragment] land.sungbin.calculation [IrFunction] name: plus [IrValueParameter] name: a, type: kotlin.Int [IrValueParameter] name: b, type: kotlin.Int IrBlockBody [IrCall] symbol: kotlin.io.println value argument: ...
  15. package fun land.sungbin.calculation

 (a: Int, b: Int) {
 println(a +

    b)
 } plus IrFile [IrPackageFragment] land.sungbin.calculation [IrFunction] name: plus [IrValueParameter] name: a, type: kotlin.Int [IrValueParameter] name: b, type: kotlin.Int IrBlockBody [IrCall] symbol: kotlin.io.println value argument: ... [IrCall] symbol: kotlin.Int.plus dispatch receiver: IrGetValue(target: a) value argument: IrGetValue(target: b)
  16. package fun land.sungbin.calculation

 (a: Int, b: Int) {
 println(a +

    b)
 } plus MODULE_FRAGMENT name:test-module FILE fqName:land.sungbin.calculation fileName:/TestSource.kt FUN name:plus visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:a index:0 type:kotlin.Int VALUE_PARAMETER name:b index:1 type:kotlin.Int BLOCK_BODY CALL 'public final fun println (message: kotlin.Int): kotlin.Unit [inline] declared in kotlin.io' type=kotlin.Unit origin=null message: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS $this: GET_VAR 'a: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null other: GET_VAR 'b: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null
  17. package land.sungbin.calculation

 fun plus(a: Int, b: Int) {
 println(a +

    b)
 } MODULE_FRAGMENT name:test-module FILE fqName:land.sungbin.calculation fileName:/TestSource.kt FUN name:plus visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:a index:0 type:kotlin.Int VALUE_PARAMETER name:b index:1 type:kotlin.Int BLOCK_BODY CALL 'public final fun println (message: kotlin.Int): kotlin.Unit [inline] declared in kotlin.io' type=kotlin.Unit origin=null message: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS $this: GET_VAR 'a: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null other: GET_VAR 'b: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null
  18. package fun land.sungbin.calculation

 (a: Int, b: Int) plus {
 println(a

    + b)
 } MODULE_FRAGMENT name:test-module FILE fqName:land.sungbin.calculation fileName:/TestSource.kt FUN name:plus visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:a index:0 type:kotlin.Int VALUE_PARAMETER name:b index:1 type:kotlin.Int BLOCK_BODY CALL 'public final fun println (message: kotlin.Int): kotlin.Unit [inline] declared in kotlin.io' type=kotlin.Unit origin=null message: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS $this: GET_VAR 'a: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null other: GET_VAR 'b: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null
  19. package fun land.sungbin.calculation

 (a: Int, b: Int) {
 println( )


    } plus a + b MODULE_FRAGMENT name:test-module FILE fqName:land.sungbin.calculation fileName:/TestSource.kt FUN name:plus visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:a index:0 type:kotlin.Int VALUE_PARAMETER name:b index:1 type:kotlin.Int BLOCK_BODY CALL 'public final fun println (message: kotlin.Int): kotlin.Unit [inline] declared in kotlin.io' type=kotlin.Unit origin=null message: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS $this: GET_VAR 'a: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null other: GET_VAR 'b: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null
  20. package fun land.sungbin.calculation

 (a: Int, b: Int) {
 println( +

    )
 } plus a b MODULE_FRAGMENT name:test-module FILE fqName:land.sungbin.calculation fileName:/TestSource.kt FUN name:plus visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:a index:0 type:kotlin.Int VALUE_PARAMETER name:b index:1 type:kotlin.Int BLOCK_BODY CALL 'public final fun println (message: kotlin.Int): kotlin.Unit [inline] declared in kotlin.io' type=kotlin.Unit origin=null message: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS $this: GET_VAR 'a: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null other: GET_VAR 'b: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null
  21. package fun land.sungbin.calculation

 (a: Int, b: Int) {
 println(a +

    )
 } plus b MODULE_FRAGMENT name:test-module FILE fqName:land.sungbin.calculation fileName:/TestSource.kt FUN name:plus visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:a index:0 type:kotlin.Int VALUE_PARAMETER name:b index:1 type:kotlin.Int BLOCK_BODY CALL 'public final fun println (message: kotlin.Int): kotlin.Unit [inline] declared in kotlin.io' type=kotlin.Unit origin=null message: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS $this: GET_VAR 'a: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null other: GET_VAR 'b: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null
  22. package fun land.sungbin.calculation

 (a: Int, b: Int) {
 println(a +

    b)
 } plus MODULE_FRAGMENT name:test-module FILE fqName:land.sungbin.calculation fileName:/TestSource.kt FUN name:plus visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:a index:0 type:kotlin.Int VALUE_PARAMETER name:b index:1 type:kotlin.Int BLOCK_BODY CALL 'public final fun println (message: kotlin.Int): kotlin.Unit [inline] declared in kotlin.io' type=kotlin.Unit origin=null message: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS $this: GET_VAR 'a: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null other: GET_VAR 'b: kotlin.Int declared in land.sungbin.calculation.plus' type=kotlin.Int origin=null
  23. data class val val fun val MyData( : Int, :

    Int) () { data = MyData( , ).toString() println(data) } a b main 1 2 // MyData(a=1, b=2)
  24. class val val fun var for in ${ } ${

    } return fun val MyData( : Int, : Int) { (): String {
 result = result += (param ) { result += param. param. }
 result += result
 } } () { data = MyData( , ).toString() println(data) } a b valueParameters name value toString main ""
 "MyData("
 " = , "
 ")"
 // [Parameter(name = "a", value = a.toString()), ..]
 // MyData(a=1, b=2) 1 2
  25. class val val fun MyData( : Int, : Int) {

    (): String {
 
 } } a b toString fun main() { val data = MyData(1, 2).toString() println(data) // MyData(a=1, b=2) } [IrFunction] name: toString, type: kotlin.String
  26. class val val fun var MyData( : Int, : Int)

    { (): String {
 result = } } a b toString "" 
 fun main() { val data = MyData(1, 2).toString() println(data) // MyData(a=1, b=2) } [IrFunction] name: toString, type: kotlin.String [IrVariable] name: result, type: kotlin.String
  27. class val val fun MyData( : Int, : Int) {

    (): String {
 result += } } a b toString var result = ""
 fun main() { val data = MyData(1, 2).toString() println(data) // MyData(a=1, b=2) } "MyData("

 [IrFunction] name: toString, type: kotlin.String [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result
  28. class val val fun for in MyData( : Int, :

    Int) { (): String {
 (param ) {
 
 } 
 } } a b valueParameters toString var result = ""
 result += "MyData("
 fun main() { val data = MyData(1, 2).toString() println(data) // MyData(a=1, b=2) } [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result
  29. class val val fun for in ${ } ${ }

    MyData( : Int, : Int) { (): String {
 (param ) {
 result += param. param. }

 } } a b valueParameters name value toString var result = ""
 result += "MyData("
 fun main() { val data = MyData(1, 2).toString() println(data) // MyData(a=1, b=2) } " = , "
 [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result
  30. class val val fun MyData( : Int, : Int) {

    (): String {
 result += } } a b toString var result = ""
 result += "MyData("
 for (param in valueParameters) {
 result += "${param.name}=${param.value}, "
 }
 fun main() { val data = MyData(1, 2).toString() println(data) // MyData(a=1, b=2) } ")"

 [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result
  31. class val val fun return MyData( : Int, : Int)

    { (): String {
 result
 } } a b toString var result = ""
 result += "MyData("
 for (param in valueParameters) {
 result += "${param.name}=${param.value}, "
 }
 result += ")"
 fun main() { val data = MyData(1, 2).toString() println(data) // MyData(a=1, b=2) } [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrReturn] target: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result
  32. class val val fun var for in ${ } ${

    } return fun val MyData( : Int, : Int) { (): String {
 result = result += (param ) {
 result += param. param. }
 result += result
 } } () { data = MyData( , ).toString() println(data) } a b valueParameters name value toString main ""
 "MyData("
 " = , "
 ")"
 1 2 // MyData(a=1, b=2) [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrReturn] target: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result
  33. [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param

    [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrReturn] target: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result fun val buildDataClassToStringReturn(
 clazz: IrClass,
 parameters: List<IrValueParameter>,
 ) {
 result = IrVariable( , )

 } name = type = "result" "kotlin.String" IrCall.fromSymbol("kotlin.String.plusAssign")
 .addValueArgument(IrConst(clazz.name + "("))
 .dispatchReceiver(result)

 IrForLoop(target = parameters, name = "param")
 .addBodyStatement(
 IrCall.fromSymbol("kotlin.String.plusAssign")
 .addValueArgument(IrConst("\${param.name}=\${param.value}, "))
 .dispatchReceiver(result)
 )

 IrCall.fromSymbol("kotlin.String.plusAssign")
 .addValueArgument(IrConst(")"))
 .dispatchReceiver(result)

 IrReturn(result)

  34. [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param

    [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrReturn] target: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result fun val buildDataClassToStringReturn(
 clazz: IrClass,
 parameters: List<IrValueParameter>,
 ) {
 result = IrVariable( , )

 IrCall.fromSymbol( )
 . (IrConst(clazz. + ))
 . (result)

 } name = type = "result" "kotlin.String" "kotlin.String.plusAssign" "(" addValueArgument dispatchReceiver name IrForLoop(target = parameters, name = "param")
 .addBodyStatement(
 IrCall.fromSymbol("kotlin.String.plusAssign")
 .addValueArgument(IrConst("\${param.name}=\${param.value}, "))
 .dispatchReceiver(result)
 )

 IrCall.fromSymbol("kotlin.String.plusAssign")
 .addValueArgument(IrConst(")"))
 .dispatchReceiver(result)

 IrReturn(result)

  35. [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param

    [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrReturn] target: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result fun val buildDataClassToStringReturn(
 clazz: IrClass,
 parameters: List<IrValueParameter>,
 ) {
 result = IrVariable( , )

 IrCall.fromSymbol( )
 . (IrConst(clazz. + ))
 . (result)

 IrForLoop( parameters, )
 } name = type = target = name = "result" "kotlin.String" "kotlin.String.plusAssign" "(" "param" addValueArgument dispatchReceiver name .addBodyStatement(
 IrCall.fromSymbol("kotlin.String.plusAssign")
 .addValueArgument(IrConst("\${param.name}=\${param.value}, "))
 .dispatchReceiver(result)
 )

 IrCall.fromSymbol("kotlin.String.plusAssign")
 .addValueArgument(IrConst(")"))
 .dispatchReceiver(result)

 IrReturn(result)

  36. fun val \$ \$ buildDataClassToStringReturn(
 clazz: IrClass,
 parameters: List<IrValueParameter>,
 )

    {
 result = IrVariable( , )

 IrCall.fromSymbol( )
 . (IrConst(clazz. + ))
 . (result)

 IrForLoop( parameters, )
 .addBodyStatement(
 IrCall.fromSymbol( )
 . (IrConst( ))
 . (result)
 )

 } name = type = target = name = "result" "kotlin.String" "kotlin.String.plusAssign" "(" "param" "kotlin.String.plusAssign" " {param.name}= {param.value}, " addValueArgument dispatchReceiver addValueArgument dispatchReceiver name IrCall.fromSymbol("kotlin.String.plusAssign")
 .addValueArgument(IrConst(")"))
 .dispatchReceiver(result)

 IrReturn(result)
 [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrReturn] target: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result
  37. fun val \$ \$ buildDataClassToStringReturn(
 clazz: IrClass,
 parameters: List<IrValueParameter>,
 )

    {
 result = IrVariable( , )

 IrCall.fromSymbol( )
 . (IrConst(clazz. + ))
 . (result)

 IrForLoop( parameters, )
 .addBodyStatement(
 IrCall.fromSymbol( )
 . (IrConst( ))
 . (result)
 )

 IrCall.fromSymbol( )
 . (IrConst( ))
 . (result)

 } name = type = target = name = "result" "kotlin.String" "kotlin.String.plusAssign" "(" "param" "kotlin.String.plusAssign" " {param.name}= {param.value}, " "kotlin.String.plusAssign" ")" addValueArgument dispatchReceiver addValueArgument dispatchReceiver addValueArgument dispatchReceiver name IrReturn(result)
 [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrReturn] target: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result
  38. fun val \$ \$ buildDataClassToStringReturn(
 clazz: IrClass,
 parameters: List<IrValueParameter>,
 )

    {
 result = IrVariable( , )

 IrCall.fromSymbol( )
 . (IrConst(clazz. + ))
 . (result)

 IrForLoop( parameters, )
 .addBodyStatement(
 IrCall.fromSymbol( )
 . (IrConst( ))
 . (result)
 )

 IrCall.fromSymbol( )
 . (IrConst( ))
 . (result)

 IrReturn(result)
 } name = type = target = name = "result" "kotlin.String" "kotlin.String.plusAssign" "(" "param" "kotlin.String.plusAssign" " {param.name}= {param.value}, " "kotlin.String.plusAssign" ")" addValueArgument dispatchReceiver addValueArgument dispatchReceiver addValueArgument dispatchReceiver name [IrFunction] name: toString, type: kotlin.String [IrForLoop] target: MyData#valueParameters, name: param [IrVariable] name: result, type: kotlin.String [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “MyData(“) dispatch receiver: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst(value: “)“) dispatch receiver: result [IrReturn] target: result [IrCall] symbol: kotlin.String.plusAssign value argument: IrConst( value: “${param.name}=${param.value}, “ ) dispatch receiver: result
  39. class val val fun var for in ${ } ${

    } return MyData( : Int, : Int) { (): String {
 result = result += (param ) {
 result += param. param. }
 result += result
 } } a b valueParameters name value // 우리가 IR로 직접 만든 toString() toString ""
 "MyData("
 " = , "
 ")"

  40. class val val fun var ${ } ${ } return

    MyData( : Int, : Int) { (): String {
 result = result += result += a.toString() result += b.toString() result += result
 } } a b // 코틀린 컴파일러가 만드는 toString() toString ""
 "MyData("
 "a= , " "b= "
 ")"

  41. fun val for in ( clazz: IrClass, parameters: List<IrValueParameter>, )

    {
 irConcat = IrStringConcatenation()
 irConcat. (IrString(clazz.name + ))

 (param parameters) {
 irConcat. (IrString(param.name + ))
 irConcat. (IrGetValue(param) + )
 }

 irConcat. (IrString( ))
 IrReturn(irConcat)
 } generateToStringMethodBody addArgument addArgument addArgument addArgument "(" "=" ", " ")" // 핵심 코드로 추상화되었습니다. // https://is.gd/kt_dc_st 에서 원본 코드 확인 가능
  42. Intermediate Representation Source Code와 Machine Code의 중간 표현. 대부분의 컴파일러는

    IR을 사용해서 Source ⭤ Machine 간의 중복 코드/작업을 최소화한다. (하나의 IR만 관리하면 모든 Machine Code에 반영됨)
  43. private fun fun val fun (): String = () {

    println(currentFunctionName()) lambda = { println(currentFunctionName()) } lambda.invoke() otherFunction() } () { println(currentFunctionName()) } currentFunctionName main otherFunction TODO() // "main" 출력 // "<anonymous>" 출력 // "otherFunction" 출력
  44. 2025. 03. 22. 각 상황 별로 Compose Compiler가 만드는 코드,

    최적화하는 코드 “모두” 알아보기 이때도 와주실거죠?