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

[Kotlin Fest 2024] もっとKotlinを好きになる!K2時代のKotlin Compiler Plugin開発

[Kotlin Fest 2024] もっとKotlinを好きになる!K2時代のKotlin Compiler Plugin開発

Kotlin Fest 2024で発表した次のセッションのスライド資料になります。
https://fortee.jp/kotlin-fest-2024/proposal/59aca818-d5d5-4eb4-a123-abae563a7f28

kitakkun

June 22, 2024
Tweet

More Decks by kitakkun

Other Decks in Programming

Transcript

  1. 2 • kitakkun / Takumi Kitagawa • X: @kitakkun_pb •

    GitHub: @kitakkun • Android Engineer @ • େֶ࣌୅͸ Kotlin Compiler Plugin
 Λ׆༻ͨ͠ݚڀΛ͍ͯ͠·ͨ͠ ొஃऀϓϩϑΟʔϧ
  2. ຊηογϣϯʹ͍ͭͯ • ର৅ • Kotlin Compiler Pluginͷ࢓૊Έɾ։ൃํ๏ʹڵຯ͕͋Δํ • औΓѻ͏಺༰ •

    Kotlin Compilerͷ಺෦ߏ଄ • Kotlin Compiler Plugin APIͷղઆ • Kotlin Compiler Pluginͷ׆༻ྫ 3
  3. Kotlin Compiler • KotlinͷιʔεϓϩάϥϜΛ࣮ߦՄೳϓϩάϥϜ΁ͱม׵ • Frontend ͱ Backend ͔Β੒Δ •

    Frontend ιʔεϓϩάϥϜͷղੳ • Backend ࠷దԽɾ໨తϓϩάϥϜʢJVM, Native, JS…ʣͷग़ྗ • K2ίϯύΠϥͰ͸ Frontend ΞʔΩςΫνϟʹେ෯มߋ 5
  4. KtTokens ※ۭനτʔΫϯ͸লུ https://github.com/JetBrains/kotlin/blob/master/compiler/psi/src/org/ jetbrains/kotlin/lexer/KtTokens.java 8 fun kotlinFest ( ) =

    " 2024 " AST/PSI kotlin.FILE: fun kotlinFest() = "2024" PACKAGE_DIRECTIVE: IMPORT_LIST: FUN: fun kotlinFest() = "2024" fun: fun WHITE_SPACE: IDENTIFIER: kotlinFest VALUE_PARAMETER_LIST: () LPAR: ( RPAR: ) WHITE_SPACE: EQ: = WHITE_SPACE: STRING_TEMPLATE: "2024" OPEN_QUOTE: " LITERAL_STRING_TEMPLATE_ENTRY: 2024 REGULAR_STRING_PART: 2024 CLOSING_QUOTE: " FIR ߏจղੳ (Parse)
  5. FIR - Frontend Intermediate Representation • Frontend ઐ༻ͷதؒදݱʢK2Ͱಋೖʣ • ίϯύΠϥ͕ίʔυʹ͍ͭͯ஌Γ͏Δ৘ใશͯΛؚΉ

    • ͍͔ͭ͘ͷϑΣʔζΛܦͯஈ֊తʹղܾ͞ΕΔ 9 K1Ͱ͸ PSI + Descriptor, BindingContext Source KtTokens AST/PSI RAW_FIR FIR Resolve
  6. FIRΛղܾ͢Δ14ϑΣʔζ ॳظͷ FIR ͸׬શͳ৘ใΛ࣋ͨͣ
 14ͷϑΣʔζͰஈ֊తʹղܾ͞ΕΔ https://github.com/JetBrains/kotlin/blob/master/ compiler/ fi r/tree/src/org/jetbrains/kotlin/ fi

    r/ declarations/FirResolvePhase.kt 10 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  7. 1. RAW_FIR 11 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES

    STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS AST͔Β௚઀ಘΒΕΔੜͷFIR ଟ͘ͷ৘ใ͕ܽམͨ͠ঢ়ଶ • γϯϘϧͷࢀরઌ • ܕ৘ใ • etc...
  8. 2. IMPORTS 12 importจΛղܾ • import͞Ε͍ͯΔγϯϘϧΛಛఆ • ύοέʔδ෦෼ͱͦΕҎ߱Ͱ෼ׂ • ྫ:

    kotlin.collections.List
 → kotlin.collections / List • classId = package + className • callableId = package + callableName RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  9. 3. COMPILER_REQUIRED_ANNOTATIONS 13 ίϯύΠϥΞϊςʔγϣϯͷܕΛղܾ • @SinceKotlin, @JvmRecord, … • @Deprecated,

    @Target͸
 Ҿ਺΋ղܾ͞ΕΔ @Deprecated("Use hoge instead") @Target(AnnotationTarget.CLASS) annotation class MyMarker RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  10. 4. COMPANION_GENERATION 14 class A { companion object { …

    } } Compiler PluginʹΑΓఏڙ͞ΕΔ
 companion object Λੜ੒ RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  11. શΫϥεͷεʔύʔλΠϓΛղܾ͠
 λΠϓΤΠϦΞεͷల։Λߦ͏ 5. SUPER_TYPES 15 class A : B() //

    AliasedC -> C open class B : AliasedC interface C typealias AliasedC = C RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  12. sealedΫϥεͷܧঝΫϥεΛه࿥ 6. SEALED_CLASS_INHERITORS 16 sealed class A data object B:

    A() data class C( ... ): A() RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  13. 7. TYPES 17 fun a(): Int = ... fun b(str:

    String) { ... } fun Int.increment() = ... class A<T: Number> annotation class Annotation ໌ࣔతʹهड़͞ΕͨܕΛղܾ RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  14. 8. STATUS 18 ϝϯόએݴͷ Status Λղܾ RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION

    SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS class A { // visibility private fun hoge() { … } // modality abstract fun fuga() // modifiers suspend fun foo() }
  15. 9. EXPECT_ACTUAL_MATCHING 19 // commonMain expect val platform: String //

    jvmMain actual val platform = "jvm" // iosMain actual val platform = "ios" MultiplatformϓϩδΣΫτͷ expectએݴͱactualએݴͷରԠ෇͚ RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  16. 10. CONTRACTS 20 contractϒϩοΫΛղܾ • contract = ίϯύΠϥͱͷ໿ଋࣄ @kotlin.internal.InlineOnly public

    inline fun <T> T.apply(block: T.() - > Unit): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() return this } ↓ block͕1౓͔͠ݺ͹Εͳ͍͜ͱΛڭ͍͑ͯΔ RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  17. 11. IMPLICIT_TYPES_BODY_RESOLVE 21 callableͳએݴͷ҉໧తͳܕΛղܾ + constϓϩύςΟͷॳظԽࣜͷղܾ fun foo() = 0

    // Int val bar = "str" // String val baz get() = foo() / / Int RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS const val a = 0 + 10
  18. 12. CONSTANT_EVALUATION 22 constϓϩύςΟͷॳظԽࣜͱ
 ΞϊςʔγϣϯҾ਺ͷσϑΥϧτ஋
 ΛධՁ const val a =

    0 + 10 ↓ const val a = 10 annotation class A(val a: Int = 10) RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  19. 13. ANNOTATION_ARGUMENTS 23 એݴ෦ͷΞϊςʔγϣϯҾ਺Λղܾ annotation class A( val a: Int

    = 10 ) @A(a = 20) class B RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  20. 14. BODY_RESOLVE 24 એݴͷຊମʢBodyʣΛղܾ fun a() { val hoge =

    object { ... } } RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  21. 14. BODY_RESOLVE (Local Declarations) 25 એݴͷຊମʢBodyʣΛղܾ ϩʔΧϧએݴΛൃݟͨ͠Β COMPILER_REQUIRED_ANNOTATIONS ~ ANNOTATION_ARGUMENTS

    ·ͰΛہॴతʹద༻ fun a() { // local declaration val hoge = object { ... } } RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  22. CHECKER 26 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS

    EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS Resolved FIR Checker RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  23. FIR2IR 27 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS

    EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS Resolved FIR Checker IR (backend) FIR2IR RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  24. Kotlin Compiler Backend 28 IR Lowered IR Target Code .class

    01101010 10101010 01011 JS JVM Native JS FIR
  25. Kotlin Compiler ·ͱΊ • Frontend ͱ Backend 2ͭͷ෦෼͔Β੒Δ • Frontend

    • ιʔείʔυͷղੳ͕ओ໨త • FIR ͱ͍͏ஈ֊తʹղܾ͞ΕΔதؒදݱΛѻ͏ • Backend • ࠷దԽ΍໨తϓϩάϥϜͷग़ྗ͕໨త • IR ͱ͍͏׬શʹ৘ใ͕ղܾ͞ΕͨதؒදݱΛѻ͏ 29
  26. Kotlin Compiler Plugin ίϯύΠϥͷ֤ม׵ϑΣʔζʹհೖ͠தؒදݱʢFIR / IRʣΛૢ࡞ 31 Compiler Frontend Compiler

    Backend KtTokens AST/PSI RAW_FIR FIR Source IR Lowered IR Target Code FIR֦ு IR֦ு
  27. Frontend֦ுʹͰ͖Δ͜ͱ • εʔύʔλΠϓͷ௥Ճ FirSupertypeGenerationExtension • એݴͷੜ੒ FirDeclarationGenerationExtension • Status ͷม׵

    FirStatusTransformerExtension • FIRνΣοΧʔͷ௥Ճ FirAdditionalCheckersExtension • … 33 https://github.com/JetBrains/kotlin/blob/master/docs/ fi r/ fi r-plugins.md
  28. FirSupertypeGenerationExtension 34 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS

    EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS class A class A : MyInterface
  29. FirStatusTransformerExtension 35 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS

    EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS class A open class A
  30. FirDeclarationGenerationExtension 36 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS

    EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS class A class A { companion object { ... } fun hoge() }
  31. FirAdditionalCheckersExtension 37 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS

    EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS Resolved FIR Checker RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS FIR CheckerΛ௥Ճ
  32. FirExtension 40 abstract class FirExtension( val session: FirSession ) {

    ... } FirSession FirSessionComponent … FirExtension શͯͷFIR֦ுͷجఈΫϥεͰ FirSession ΁ͷࢀরΛ࣋ͭ
  33. FirSession 41 abstract class FirSession @PrivateSessionConstructor constructor( val sessionProvider: FirSessionProvider?,

    val kind: Kind ) : ComponentArrayOwner<FirSessionComponent, FirSessionComponent>() { // ... } FirSession FirSessionComponent … FirExtension • FIRίϯύΠϧηογϣϯͷ؅ཧ୯Ґ • FirSessionComponentΛଋͶ͍ͯΔ
  34. FirExtension ͱ Predicate • શͯͷFIR֦ு͸ʮPredicateʯΛج࣠ʹઃܭ • Predicate ≒ γϯϘϧͷϚονϯάύλʔϯ •

    ΞϊςʔγϣϯΛϕʔεʹॲཧର৅Λಛఆ • Ϣʔβʔ͕FIRίϯύΠϥʹࢦࣔΛग़͢།Ұͷʢਖ਼ࣜͳʣํ๏ 44 abstract class FirExtension(val session: FirSession) { open fun FirDeclarationPredicateRegistrar.registerPredicates() {} }
  35. 2छྨͷPredicate • LookupPredicate Ϛον͢ΔγϯϘϧϦετΛฦ٫ • DeclarationPredicate એݴ͕Ϛον͢Δ͔൑ఆ (true or false)

    • ಺෦తͳ࢖ΘΕํ͕एׯҟͳΔ͚ͩͰେ͖ͳҧ͍͸ͳ͍ • DeclarationPredicate Λ࢖͏͜ͱ͕ଟ͍ 45
  36. Predicateʹ࢖͑Δύλʔϯ 47 @Marker class A { fun b() } annotatedOrUnder(FqName("Marker"))

    annotated(FqName("Marker")) parentAnnotated(FqName("Marker"))
  37. Q: ௨ৗͷΞϊςʔγϣϯ͕ղܾ͞ΕΔϑΣʔζ͸ʁ 49 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES

    STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  38. Q: ௨ৗͷΞϊςʔγϣϯ͕ղܾ͞ΕΔϑΣʔζ͸ʁ 50 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES

    STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS ͜͜Ͱ͢ʂ
  39. Q: FIR֦ு͕ؔ࿈͢ΔϑΣʔζ͸ʁ 51 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES

    STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  40. Q: FIR֦ு͕ؔ࿈͢ΔϑΣʔζ͸ʁ 52 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES

    STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  41. Q: FIR֦ு͕ؔ࿈͢ΔϑΣʔζ͸ʁ 53 RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES

    STATUS EXPECT_ACTUAL_MATCHING CONTRACTS IMPLICIT_TYPES_BODY_RESOLVE CONSTANT_EVALUATION BODY_RESOLVE ANNOTATION_ARGUMENTS
  42. Predicateʹؔ͢Δ஫ҙ఺ 55 • Predicate Ͱ༻͍ΔΞϊςʔγϣϯ͸
 COMPILER_REQUIRED_ANNOTATIONS Ͱ
 ղܾࡁΈͰͳ͚Ε͹ͳΒͳ͍ • FirExtension

    ͷ registerPredicates Λ࣮૷͠
 Predicate Λ࠷ॳʹొ࿥͓ͯ͘͠ RAW_FIR IMPORTS COMPILER_REQUIRED_ANNOTATIONS COMPANION_GENRATION SUPER_TYPES SEALED_CLASS_INHERITORS TYPES EXPEC IMPLICIT CON ANNO
  43. IrPluginContext IRͷૢ࡞ʹ໾ཱͭػೳΛఏڙ • ֤छ IrSymbol ΁ͷΞΫηε • referenceClass • referenceFunctions

    • referenceProperties • referenceConstructors • … • irFactory, irBuiltIns ͳͲIRվมʹ໾ཱͭίϯϙʔωϯτΛ࣋ͭ 61
  44. IRϊʔυͷղੳ • IrElementVisitor Λ༻͍ͯ
 ֤छ IRϊʔυΛ๚໰Ͱ͖Δ 62 IrClass IrSimpleFunction IrFile

    IrModuleFragment visitFile visitClass visitSimpleFunction IrFile IrProperty … …
  45. Backend֦ுͷ·ͱΊ • ར༻Ͱ͖Δ֦ு͸ IrGenerationExtension • IrModuleFragment = ϞδϡʔϧͷIRج఺ϊʔυ • IrPluginContext

    = IRվมʹศརͳػೳΛఏڙ • IRͷղੳʹ͸ IrElementVisitor Λ࢖͏ • IRͷվมʹ͸ IrElementTransformer Λ࢖͏ 64
  46. The Inside of Greeting Compiler Plugin 79 @Greetable class LovelyClass

    { fun greet(name: String) } FIR֦ுͰੜ੒
  47. The Inside of Greeting Compiler Plugin 80 @Greetable class LovelyClass

    { fun greet(name: String) { println("LovelyClassʮ͜Μʹͪ͸ɺ$nameʂʯ") } } IR֦ுͰੜ੒
  48. ϓϩδΣΫτશମͷϏϧυઃఆ 82 // settings.gradle.kts dependencyResolutionManagement { repositories { mavenCentral() }

    } include(":greeting-annotations") include(":greeting-compiler") include(":test") // build.gradle.kts (project root) plugins { kotlin("jvm") version "2.0.0" apply false } greeting-plugin build.gradle.kts settings.gradle.kts
  49. … ίϯύΠϥϓϥάΠϯͷϏϧυઃఆ ( :greeting-compiler ) 84 plugins { kotlin("jvm") }

    dependencies { implementation( kotlin("compiler-embeddable") ) } greeting-compiler build.gradle.kts greeting-annotations greeting-plugin
  50. ϓϥάΠϯݕূ༻ϞδϡʔϧͷϏϧυઃఆ ( :test ) 85 plugins { kotlin("jvm") } dependencies

    { testImplementation(kotlin("test")) testCompileOnly( project(":greeting-annotations") ) kotlinCompilerPluginClasspath( project(":greeting-compiler") ) } build.gradle.kts test … greeting-compiler greeting-annotations greeting-plugin
  51. class GreetingFirDeclarationGenerationExtension(session: FirSession) : FirDeclarationGenerationExtension(session) { override fun getCallableNamesForClass( classSymbol:

    FirClassSymbol <*> , context: MemberGenerationContext ): Set<Name> = TODO() override fun generateFunctions( callableId: CallableId, context: MemberGenerationContext? ): List<FirNamedFunctionSymbol> = TODO() } 94 Name.identi er("greet") Λฦ͢ fun greet(name: String): String Λੜ੒
  52. class GreetingFirDeclarationGenerationExtension(session: FirSession) : FirDeclarationGenerationExtension(session) { override fun getCallableNamesForClass( classSymbol:

    FirClassSymbol <* > , context: MemberGenerationContext ): Set<Name> { if (session.predicateBasedProvider.matches(greetablePredicate, classSymbol)) { return setOf(Name.identifier("greet")) } return emptySet() } // .. . } 95 @Greetable class A
  53. class GreetingFirDeclarationGenerationExtension(session: FirSession) : … { override fun getCallableNamesForClass( ...

    ) : Set<Name> { .. . } override fun generateFunctions( callableId: CallableId, context: MemberGenerationContext? ): List<FirNamedFunctionSymbol> { return listOf( createMemberFunction( owner = context ? . owner ?: return emptyList(), key = GreetingDeclarationKey, name = callableId.callableName, returnType = session.builtinTypes.unitType.type, config = { valueParameter(Name.identifier("name"), session.builtinTypes.stringType.type) } ).symbol ) } } 96 fun greet(name: String)
  54. Predicateͷొ࿥ʢ๨Εͣʹʂʂʣ 97 class GreetingFirDeclarationGenerationExtension(session: FirSession) : FirDeclarationGenerationExtension(session) { // .

    .. override fun FirDeclarationPredicateRegistrar.registerPredicates() { register(greetablePredicate) } } registerPredicates Ͱ @Greetable ͷ Predicate Λొ࿥
  55. IR֦ுͰߦ͏͜ͱ 99 @Greetable class LovelyClass { fun greet(name: String) {

    println("LovelyClassʮ͜Μʹͪ͸ɺ$nameʂʯ") } } ؔ਺ຊମͷੜ੒
  56. IR֦ுͰߦ͏͜ͱ 100 @Greetable class LovelyClass { fun greet(name: String) {

    print("LovelyClassʮ͜Μʹͪ͸ɺ") print(name) println("ʂʯ") } } IRੜ੒͠΍͍͢ܗࣜʹมߋ
  57. IrGenerationExtension ͷ࣮૷ 102 package greeting.compiler.ir class GreetingIrGenerationExtension() : IrGenerationExtension {

    // ... } greeting-compiler src/main/kotlin greeting.compiler.ir GreetingIrGenerationExtension.kt
  58. IrGenerationExtension ͷ࣮૷ 103 package greeting.compiler.ir class GreetingIrGenerationExtension() : IrGenerationExtension {

    override fun generate( moduleFragment: IrModuleFragment, pluginContext: IrPluginContext ) { moduleFragment.transformChildrenVoid( GreetingIrElementTransformer(pluginContext) ) } }
  59. IrElementTransformerVoid ͷ࣮૷ 105 package greeting.compiler.ir class GreetingIrElementTransformer( private val pluginContext:

    IrPluginContext ) : IrElementTransformerVoid() { private val printFunctionSymbol: IrSimpleFunctionSymbol = TODO() private val printlnFunctionSymbol: IrSimpleFunctionSymbol = TODO() override fun visitSimpleFunction(declaration: IrSimpleFunction) : IrStatement = TODO() }
  60. IrElementTransformerVoid ͷ࣮૷ 106 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { private val

    printFunctionSymbol = pluginContext.referenceFunctions( CallableId(FqName("kotlin.io"), Name.identifier("print")) ) ... // . .. }
  61. IrElementTransformerVoid ͷ࣮૷ 107 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { private val

    printFunctionSymbol = pluginContext.referenceFunctions( CallableId(FqName("kotlin.io"), Name.identifier("print")) ).single { it.owner.valueParameters.singleOrNull() ? . type == pluginContext.irBuiltIns.anyNType } // . .. }
  62. IrElementTransformerVoid ͷ࣮૷ 108 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { private val

    printFunctionSymbol = pluginContext.referenceFunctions( CallableId(FqName("kotlin.io"), Name.identifier("print")) ).single { it.owner.valueParameters.singleOrNull() ? . type == pluginContext.irBuiltIns.anyNType } private val printlnFunctionSymbol = pluginContext.referenceFunctions( CallableId(FqName("kotlin.io"), Name.identifier("println")) ).single { it.owner.valueParameters.singleOrNull() ? . type == pluginContext.irBuiltIns.anyNType } … }
  63. IrElementTransformerVoid ͷ࣮૷ 109 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { private val

    printFunctionSymbol = … ✅ private val printlnFunctionSymbol = … ✅ // TODO: FIRͰੜ੒ͨ͠એݴͷຊମΛੜ੒ override fun visitSimpleFunction(declaration: IrSimpleFunction) : IrStatement = TODO() }
  64. 110 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { // . .. override

    fun visitSimpleFunction(declaration: IrSimpleFunction) : IrStatement { } } // TODO1: ؔ܎ͷͳ͍ؔ਺Λແࢹ // TODO2: greetؔ਺ͷbodyΛੜ੒
  65. 111 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { // . .. override

    fun visitSimpleFunction(declaration: IrSimpleFunction) : IrStatement { // TODO1: ؔ܎ͷͳ͍ؔ਺Λແࢹ val origin = declaration.origin as? IrDeclarationOrigin.GeneratedByPlugin if (origin ? . pluginKey !is GreetingDeclarationKey) return declaration // ... } } Fir֦ுͰੜ੒ͨ͠ DeclarationKey 
 Λ͍࣋ͬͯΔ͔νΣοΫ
  66. 112 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { // .. . override

    fun visitSimpleFunction(declaration: IrSimpleFunction) : IrStatement { / / . .. / / TODO2: greetؔ਺ͷbodyͷੜ੒ val irBuilder = pluginContext.irBuiltIns.createIrBuilder(declaration.symbol) declaration.body = irBuilder.irBlockBody { // print("Ϋϥε໊ʮ͜Μʹͪ͸ɺ") // print(name) // println("ʂʯ") } return declaration } }
  67. 113 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { // .. . override

    fun visitSimpleFunction(declaration: IrSimpleFunction) : IrStatement { / / . .. / / TODO2: greetؔ਺ͷbodyͷੜ੒ val irBuilder = pluginContext.irBuiltIns.createIrBuilder(declaration.symbol) declaration.body = irBuilder.irBlockBody { // print("Ϋϥε໊ʮ͜Μʹͪ͸ɺ") // print(name) // println("ʂʯ") } return declaration } }
  68. 114 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { // .. . override

    fun visitSimpleFunction(declaration: IrSimpleFunction) : IrStatement { / / . .. / / TODO2: greetؔ਺ͷbodyͷੜ੒ val irBuilder = pluginContext.irBuiltIns.createIrBuilder(declaration.symbol) declaration.body = irBuilder.irBlockBody { // print("Ϋϥε໊ʮ͜Μʹͪ͸ɺ") // print(name) // println("ʂʯ") } return declaration } }
  69. 115 class GreetingIrElementTransformer(…) : IrElementTransformerVoid() { // ... override fun

    visitSimpleFunction(declaration: IrSimpleFunction) : IrStatement { // . . . val irBuilder = pluginContext.irBuiltIns.createIrBuilder(declaration.symbol) val parentClassName = declaration.parentClassOrNull ?. kotlinFqName ? . asString() declaration.body = irBuilder.irBlockBody { +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irString("$parentClassNameʮ͜Μʹͪ͸ɺ")) } +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irGet(declaration.valueParameters.single())) } +irCall(printlnFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irString("ʂʯ")) } } return declaration } }
  70. 116 // print("Ϋϥε໊ʮ͜Μʹͪ͸ɺ") +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument =

    irString("$parentClassNameʮ͜Μʹͪ͸ɺ")) } // print(name) +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irGet(declaration.valueParameters.single())) } // println("ʂʯ") +irCall(printlnFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irString("ʂʯ")) }
  71. 117 // print("Ϋϥε໊ʮ͜Μʹͪ͸ɺ") +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument =

    irString("$parentClassNameʮ͜Μʹͪ͸ɺ")) } // print(name) +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irGet(declaration.valueParameters.single())) } // println("ʂʯ") +irCall(printlnFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irString("ʂʯ")) }
  72. 118 // print("Ϋϥε໊ʮ͜Μʹͪ͸ɺ") +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument =

    irString("$parentClassNameʮ͜Μʹͪ͸ɺ")) } // print(name) +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irGet(declaration.valueParameters.single())) } // println("ʂʯ") +irCall(printlnFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irString("ʂʯ")) }
  73. 119 // print("Ϋϥε໊ʮ͜Μʹͪ͸ɺ") +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument =

    irString("$parentClassNameʮ͜Μʹͪ͸ɺ")) } // print(name) +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irGet(declaration.valueParameters.single())) } // println("ʂʯ") +irCall(printlnFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irString("ʂʯ")) }
  74. 120 // print("Ϋϥε໊ʮ͜Μʹͪ͸ɺ") +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument =

    irString("$parentClassNameʮ͜Μʹͪ͸ɺ")) } // print(name) +irCall(printFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irGet(declaration.valueParameters.single())) } // println("ʂʯ") +irCall(printlnFunctionSymbol).apply { putValueArgument(index = 0, valueArgument = irString("ʂʯ")) }
  75. CompilerPluginRegistrar ֤छ Extension Λొ࿥͢ΔαʔϏε 123 CompilerPluginRegistrar FirExtensionRegistrar IrGenerationExtension FirExtension FirExtension

    … CompilerCon fi guration get(…) FirExtensionRegistrarAdapter registerExtension(…) registerExtension(…)
  76. CompilerPluginRegistrar ͷ࣮૷ ( :greeting-compiler ) 124 package greeting.compiler class GreetingCompilerPluginRegistrar

    : CompilerPluginRegistrar() { override val supportsK2: Boolean = true override fun ExtensionStorage.registerExtensions( configuration: CompilerConfiguration, ) { FirExtensionRegistrarAdapter.registerExtension(TODO()) IrGenerationExtension.registerExtension(TODO()) } }
  77. CompilerPluginRegistrar ͷ࣮૷ ( :greeting-compiler ) 125 package greeting.compiler class GreetingCompilerPluginRegistrar

    : CompilerPluginRegistrar() { override val supportsK2: Boolean = true override fun ExtensionStorage.registerExtensions( configuration: CompilerConfiguration, ) { FirExtensionRegistrarAdapter.registerExtension(TODO()) IrGenerationExtension.registerExtension(TODO()) } }
  78. CompilerPluginRegistrar ͷ࣮૷ ( :greeting-compiler ) 126 package greeting.compiler class GreetingCompilerPluginRegistrar

    : CompilerPluginRegistrar() { override val supportsK2: Boolean = true override fun ExtensionStorage.registerExtensions( configuration: CompilerConfiguration, ) { FirExtensionRegistrarAdapter.registerExtension(TODO()) IrGenerationExtension.registerExtension(TODO()) } }
  79. CompilerPluginRegistrar ͷ࣮૷ ( :greeting-compiler ) 127 package greeting.compiler class GreetingCompilerPluginRegistrar

    : CompilerPluginRegistrar() { override val supportsK2: Boolean = true override fun ExtensionStorage.registerExtensions( configuration: CompilerConfiguration, ) { FirExtensionRegistrarAdapter.registerExtension(TODO()) IrGenerationExtension.registerExtension(GreetingIrGenerationExtension()) } }
  80. CompilerPluginRegistrar ͷ࣮૷ ( :greeting-compiler ) 128 class GreetingCompilerPluginRegistrar : CompilerPluginRegistrar()

    { override val supportsK2: Boolean = true override fun ExtensionStorage.registerExtensions( configuration: CompilerConfiguration, ) { FirExtensionRegistrarAdapter.registerExtension( GreetingFirExtensionRegistrar() ) IrGenerationExtension.registerExtension(GreetingIrGenerationExtension()) } }
  81. FirExtensionRegistrar ʢFIR֦ுͷొ࿥ʣ 129 package greeting.compiler.fir class GreetingFirExtensionRegistrar : FirExtensionRegistrar() {

    // ֤छFIRͷϑΝΫτϦʔΛ + :: Λ࢖ͬͯొ࿥ override fun ExtensionRegistrarContext.configurePlugin() { + :: GreetingFirDeclarationGenerationExtension } }
  82. ςετΛॻ͍ͯΈΑ͏ʢ :test ʣ 132 package greeting.test @Greetable class LovelyClass class

    GreetingTest { @Test fun test() { val lovelyClass = LovelyClass() lovelyClass.greet(name = "ੈք") } }
  83. ͋Ε΋͜Ε΋ Kotlin Compiler Plugin • Compose Compiler • KSP (Kotlin

    Symbol Processing) • kotlinx.serialization • Detekt • Kapt • … 135
  84. back-in-time-pluginͷ࢓૊Έ 139 Runtime App Debugger ঢ়ଶมߋͷ௨஌ ঢ়ଶͷר͖໭͠ཁٻ Compile time Source

    Kotlin Compiler Plugin Target Code
 (with TTD code) ঢ়ଶมߋͷ௥੻ ঢ়ଶר͖໭͠༻ؔ਺ͷੜ੒
  85. back-in-time-plugin Λ࢖͏ͨΊʹඞཁͳ͜ͱ 140 @BackInTime class CounterViewModel : ViewModel() { var

    counter by mutableIntStateOf(0) private set fun increment(amount: Int) { counter += amount } }
  86. back-in-time-plugin • https://github.com/kitakkun/back-in-time-plugin • KMPରԠத • ௨৴෦෼Λ Flipper ͔Β Ktor

    ͷϐϡΞͳ WebSocket ΁มߋ • σόοΨ࣮૷Λ Flipper Plugin ͔Β Compose ΞϓϦ΁มߋ 142
  87. ࢀߟจݙ • աڈηογϣϯ • KotlinConf 2018 - Writing Your First

    Kotlin Compiler Plugin by Kevin Most • Crash Course on the Kotlin Compiler by Amanda Hinchman-Dominguez • K2 Compiler plugins by Mikhail Glukhikh • K2΁ͷಓɻίϯύΠϥΛ࡞Γ௚ͬͯ͢Ͳ͏͍͏͜ͱʁ / Kotlin Fest 2022 • KotlinެࣜϦϙδτϦ • https://github.com/JetBrains/kotlin/blob/master/docs/ fi r/ fi r-basics.md • https://github.com/JetBrains/kotlin/blob/master/docs/ fi r/ fi r-plugins.md 144