https://kotlinlang.org logo
Docs
Join the conversationJoin Slack
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by Linen
compiler
  • m

    mcpiroman

    05/25/2022, 8:41 AM
    I can call
    internal
    symbols from other modules using `@Suppress("INVISIBLE_MEMBER")`or
    "INVISIBLE_REFERENCE"
    . However that does not work for internal setter on a property. How can I suppress
    Cannot assign to ...: the setter is internal in ...
    ?
    e
    y
    d
    • 4
    • 11
  • d

    Didier Villevalois

    05/28/2022, 10:34 AM
    Hi all, I am looking for an equivalent of
    IrGenerationExtension
    but at the level of the FIR (i.e. after semantic resolution but before the lowerings). I know that FIR is still in active development but maybe there are already something that I can use. Thanks a lot to you all for any help you can provide me.
    r
    m
    d
    • 4
    • 24
  • j

    Jack Darlington

    05/29/2022, 6:00 PM
    Hi all, I have created a gradle plugin with KotlinCompilerPluginSupportPlugin. On top, have a compiler plugin, which extends kotlin-compiler-embeddable I have set kotlin.native.useEmbeddableCompilerJar=true, and I can now hook in to my ComponentRegistrar from compileKotlinLinuxX64 However, When I try and run the same for JVM. The ComponentRegistrar is never called. Is there a step I am missing when I apply the plugin to start the compilerPlugin for JVM too?
    y
    • 2
    • 15
  • m

    mbonnin

    05/30/2022, 12:26 PM
    Can I disambiguate between something that's available on the Companion vs the class itself?
    class Foo {
      object bar {}
    
      companion object {
        val bar = "companion bar"
      }
    }
    
    // I can read the companion bar
    println(Foo.bar) // companion bar
    // How do I access the object bar?
    println(Foo.??)
    s
    w
    +2
    • 5
    • 19
  • a

    Alexander Maryanovsky

    05/31/2022, 9:34 AM
    Someone is confused here. Is it IntelliJ or the compiler? Kotlin 1.6.21
    e
    • 2
    • 7
  • a

    Alexander Maryanovsky

    06/01/2022, 5:33 PM
    val evenCount = listOf(1, 2, 3).sumOf { if (it % 2 == 0) 1 else 0 }
    says
    sumOf
    is ambiguous (can’t decide between a version that returns Int and one that returns Long), but this compiles fine:
    val evenCount = listOf(1, 2, 3).sumOf { 0 + if (it % 2 == 0) 1 else 0 }
    e
    f
    • 3
    • 12
  • y

    Youssef Shoaib [MOD]

    06/04/2022, 11:57 AM
    Using FIR with Context Receivers, I'm getting
    java.lang.IllegalArgumentException: No argument for parameter VALUE_PARAMETER name:_context_receiver_1 index:1
    . The printed IR shows that the function I'm calling has a dispatch receiver, 2 context receivers, and a normal parameter, but the IR calls it just by providing the dispatch receiver and the parameter:
    CALL 'public abstract fun display <T1, SubT1> (_context_receiver_0: <root>.Kind<T1 of <root>.Display.display, SubT1 of <root>.Display.display>, _context_receiver_1: <root>.Display<SubT1 of <root>.Display.display, SubT1 of <root>.Display.display>, t1: T1 of <root>.Display.display): kotlin.String declared in <root>.Display' type=kotlin.String origin=null
      <T1>: SubT1 of <root>.ListDisplay.display$lambda-0
      <SubT1>: SubT1 of <root>.ListDisplay.display$lambda-0
      $this: GET_FIELD 'FIELD FIELD_FOR_CAPTURED_VALUE name:$_context_receiver_1 type:<root>.Display<SubT1 of <root>.ListDisplay.display$lambda-0, SubT1 of <root>.ListDisplay.display$lambda-0> visibility:public/*package*/ [final]' type=<root>.Display<SubT1 of <root>.ListDisplay.display$lambda-0, SubT1 of <root>.ListDisplay.display$lambda-0> origin=null
        receiver: GET_VAR '<this>: <root>.ListDisplay.display$lambda-0.<no name provided> declared in <root>.ListDisplay.display$lambda-0.<no name provided>.invoke' type=<root>.ListDisplay.display$lambda-0.<no name provided> origin=null
      _context_receiver_0: TYPE_OP type=SubT1 of <root>.ListDisplay.display$lambda-0 origin=CAST typeOperand=SubT1 of <root>.ListDisplay.display$lambda-0
        GET_VAR 'it: kotlin.Any? declared in <root>.ListDisplay.display$lambda-0.<no name provided>.invoke' type=kotlin.Any? origin=null
    Is this even worth reporting? Because it seems like FIR obviously doesn't support the basic functionality of context receivers. Is there anywhere I can see the progress of FIR at least? any specific youtrack issues I should be on the lookout for?
    d
    • 2
    • 7
  • a

    alp

    06/06/2022, 2:17 AM
    Hi everyone, I have a question and not sure if it is a best channel to ask so please let me know if I should ask somewhere else. I also left a question on SO but seems like it is not a very popular topic there. Prerequisites: I’m using
    "org.jetbrains.kotlin:kotlin-compiler-embeddable:1.5.32"
    , the project targets JVM only(android), and I create a simple gradle plugin to analyze some kotlin source files. I create a
    KotlinCoreEnvironment
    and pass there all the paths to analyze. I add them to the config like:
    configuration.addKotlinSourceRoots(kotlinFiles)
    configuration.addJvmClasspathRoots(classpath)
    Then I create the binding context like:
    analyzer.analyzeAndReport(files) {
        TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
            environment.project,
            files,
            NoScopeRecordCliBindingTrace(),
            environment.configuration,
            environment::createPackagePartProvider,
            ::FileBasedDeclarationProviderFactory
        )
    }
    
    return analyzer.analysisResult.bindingContext // I use this bindingContext
    I have the binding context and start analyzing the file. The goal is to get some types and classes for methods from the expressions like:
    Foo()
      .bar() // returns Bar object
      .baz() // returns Baz object
    where
    Foo
    ,
    Bar
    and
    Baz
    are 3 different classes in different kt files.I want to understand all the types by parsing such piece of code but not able to. I searched this channel for
    BindingContext
    ,
    BindingTrace
    and other keywords but nothing worked for me. I tried calling
    getResolvedCall
    and
    getCall
    on above expressions, everything returns null, same for trying to get
    Type
    or anything that I think may help me to resolve the target file that contains the functions from the code snippet above. Also, played with
    BindingUtils
    with no luck. I’m just learning how compiler works but the information is relatively limited so I mostly use some existing projects to understand the internals. Please let me know how if what I’m indenting to do is achievable. Thanks in advance
    s
    • 2
    • 15
  • q

    Quantum64

    06/06/2022, 9:30 PM
    Is there any news on when kotlin contracts will be stabilized?
    e
    d
    g
    • 4
    • 5
  • o

    Oliver.O

    06/07/2022, 6:24 PM
    With Kotlin 1.6.21 and above, what is the current purpose of the task
    compileCommonMainKotlinMetadata
    ? Second question in 🧵.
    d
    d
    • 3
    • 7
  • z

    zsqw123

    06/08/2022, 8:40 AM
    I created a KtFile in memory using my custom IDE plugin and then used
    PsiElementFinder
    to make the elements in it correctly recognized by the IDE, but I encountered the error
    Kotlin light classes should not be found by JavaPsiFacade
    , I would like to know what is the replacement for the
    PsiElementFinder
    extension point of the java idea plugin in kotlin?
    • 1
    • 1
  • a

    alaershov

    06/09/2022, 7:00 AM
    Hi! I've read somewhere about the fact that pure Kotlin projects compile faster than mixed Kotlin + Java projects. Don't remember the source, but is this even true? Or is it just a misconception, or a thing of the past? In other words, is it worth it to convert all Java files to Kotlin for faster compilation?
    s
    • 2
    • 1
  • y

    Youssef Shoaib [MOD]

    06/09/2022, 9:45 PM
    Here's some convenience extension funs I created for
    BindingContext
    , using context receivers and based on the utility functions that are peppered around
    kotlin-compiler-embeddable
    . Hopefully, this will find some use, at least before FIR takes over
    a
    • 2
    • 1
  • y

    Youssef Shoaib [MOD]

    06/10/2022, 3:00 PM
    Is there any (recommended) way to test FIR plugins? I know it's still completely unstable, but I'd like to try out a few things. I tried using kotlin-compile-testing (which I already use for testing IR plugins) but the compiler complained about K2 not supporting plugins. Looking at fir-plugin-prototype, there's some mentions of a Kotlin compiler testing API, but I can't figure out what artifact it lives in or how to even use it. Is there any way to just let the K2 compiler accept that I'm using plugins? And if not, is there any basic guidance on using the Kotlin compiler testing API that fir-plugin-prototype uses?
    s
    d
    +2
    • 5
    • 31
  • s

    server

    06/11/2022, 6:55 AM
    what is the best template for writing compiler plugins? I'd like to have something with unit tests and sample project. I cannot find anything good enough. I can take existing project and just cut it down. any ideas?
    d
    q
    t
    • 4
    • 10
  • b

    Big Chungus

    06/12/2022, 11:13 AM
    Did anyone figured out how to replace IrFunctionAccessExpression with another one in BE IR? I really don't want to rewrite an entire function just to replace a single function invocation
    s
    • 2
    • 7
  • s

    sam

    06/21/2022, 9:22 AM
    I'm trying to add a top level function which I can then invoke from native using
    -entry
    I can see the function looks ok using dump, but I get an error saying it cannot be found. If I create the function manually, then it looks identical to my generated output. Is there something special that needs to be done for the native task to pick up the entry point ?
    y
    • 2
    • 6
  • t

    Tyler Rockwood

    06/21/2022, 7:18 PM
    What is the best forum to submit compiler performance problems? Should I just dump stuff in Youtrack? Our entire backend is written in kotlin (~400 files and around of 80k lines of code) and compilation times have degraded significantly over the last 6 months of kotlinc releases and the increase of code in our repo. As context we use Bazel instead of Gradle as our build system - so there is no incremental compilation, we've been splitting our modules into small pieces to allow for Bazel to do compilation avoidance, but it's still not enough. For some concrete numbers we have a 23 line file that has a single object with one function that takes ~6 seconds to compile. Below is the output of one run when I add the
    -Xreport-perf
    flag to the compiler run.
    info: PERF: <redacted_module_name>, 1 files (23 lines)
    info: PERF: INIT: Compiler initialized in 1758 ms
    info: PERF:         ANALYZE    4307 ms       5.340 loc/s
    info: PERF:  IR TRANSLATION     289 ms      79.585 loc/s
    info: PERF:     IR LOWERING     494 ms      46.559 loc/s
    info: PERF:   IR GENERATION     348 ms      66.092 loc/s
    info: PERF:        GENERATE     842 ms      27.316 loc/s
    info: PERF: GC time for G1 Young Generation is 47 ms, 2 collections
    info: PERF: GC time for G1 Old Generation is 0 ms, 0 collections
    info: PERF: JIT time is 22892 ms
    info: PERF: Find Java class performed 11 times, total time 234 ms
    info: PERF: Type info performed 39 times, total time 2214 ms
    info: PERF: Call resolve performed 38 times, total time 2116 ms
    info: PERF: Binary class from Kotlin file performed 210 times, total time 226 ms
    We've tried to turn on
    -Xbackend-threads
    but that fails due to https://youtrack.jetbrains.com/issue/KT-52824. In general we don't have any compiler plugin ourselves, although Bazel uses
    jvm-abi-gen
    for better compilation avoidance. Are we just hopeless until K2? I've ran across issues like https://youtrack.jetbrains.com/issue/KT-38101 that performance issues (at least in the analyze phase) are being fixed in K2 (which we can't try in alpha yet because of the missing support for plugins). In the release notes for Kotlin 1.7 there was a section that posted performance numbers and there are current packages getting 1-2K loc/s with the current compiler. Even our largest modules (assuming there is some constant overhead that is making the above example so bad) maxes out at about 100 loc/s (5.8k lines in 5 files taking around 57 seconds). Are the Bazel kotlin rules invoking the compiler incorrectly to lead to such bad performance? I'm happy to talk though the threading model and how the Bazel rules invoke the compiler with someone if that turns out to be the issue.
    d
    • 2
    • 4
  • t

    turansky

    06/22/2022, 12:54 AM
    Is it possible to check
    is
    and
    as
    expressions? Is there
    DeclarationChecker
    analog for such checks?
    y
    d
    • 3
    • 3
  • d

    David Bieregger

    06/22/2022, 4:02 PM
    Just stumpled accross this and though this should be a feature: 1. Optional catch variable
    try {
        throw Error("Oh no!")
    } catch {
        console.log("Something bad happened, but don't know what")
    }
    This saves you to write the unneccessary term:
    (e: Exception)
    or
    (_: Throwable)
    2. Elvis operator for exceptions maybe with a excalmation mark
    !:
    ?
    var result = methodThatMightThrowAnError() !: return null
    If you like it or not it's a very common pattern in libraries to use exceptions as method result. Even though the exception doesn't tell you any thing important it's essential to caputure those exceptions to know that the method didn't succeed. A realworld example would be:
    inline fun <reified T> validateSignedToken(token: String) =
        try {
            Json.decodeFromString<T>(jwtVerifier.verify(token).getClaim("payload").asString())
        } catch (e: Exception) {
            null
        }
    It can be reduced to:
    inline fun <reified T> validateSignedToken(token: String) =
            Json.decodeFromString<T>(jwtVerifier.verify(token).getClaim("payload").asString()) !: null
    And yes it a bit a code golf, but I think this is Kotlin a lot about. Making thinks things very short and concise. When you don't need the Exception why spend writing the type for every try catch block? I can imagine it beeing used in a Unit Testing project as follows:
    fun insertTokenTest() {
       assertNoException {
          val person = fetchToken() !: "12345678" //This might cause an exception, but when it is not available we just don't mind an use an default value
          Database.insertToken(person)
      }
    }
    
    
    fun assertNoException(block: () -> Unit) =
        block() !: throw Error("No exception is expected")
    I think I have seen this operator already somewhere, but don't know where. Does this already have a name? Otherwise does somebody know a famous person with such a hairdo? ;)
    ➖ 2
    👍 1
    e
    • 2
    • 3
  • z

    Zac Sweers

    06/22/2022, 4:04 PM
    Same answer as your other thread. This is just code golf to avoid writing
    (_: Throwable)
    . And intentionally ignoring an exception seems like a code smell. Definitely think this would encourage far more problems than it solves
    d
    • 2
    • 1
  • n

    Nick

    06/22/2022, 7:16 PM
    Not sure where to ask, so trying here first. Is there a way to disable the build output file that seems to be created each time? It has a name that ends with compiler.options. I see a new one every time I build with the IDE.
  • t

    turansky

    06/23/2022, 9:48 PM
    What is the simplest option to disable autobox for value class?
    value class Age(value: Int)
    
    val age = Age(42)
    println(age) // AUTOBOX DISABLING REQUIRED
    In
    IrElementTransformer
    I can receive
    age
    as
    IrGetValue
    . Which processing required after?
    i
    m
    • 3
    • 3
  • c

    Christian Maus

    06/28/2022, 5:49 PM
    I’m not sure if I hit a compiler limitation or a bug regarding context receivers. In the following example, the value
    program
    , which is a contextual function can not be evaluated when the context parameter is brought into scope. Should I file a bug report? 🤔
    fun interface Context1 {
        fun c1(): Int
    }
    
    fun interface Context2 {
        fun c2(v: Int): String
    }
    
    
    context(Context1)
    fun useC1(): context(Context2) (Int) -> String {
        val x = c1()
        return { c2(it + x) }
    }
    
    fun main(args: Array<String>) {
        val program: context(Context2) (Int) -> String = with(Context1 { 42 }) {
            useC1()
        }
    
        //this works
        val result = program(Context2 { "the value is $it" }, 2)
       
        //but this doesn't work
        with(Context2 { "the value is $it" }) {
            program(2)
        }
    }
    d
    y
    • 3
    • 5
  • j

    Javier

    06/29/2022, 11:01 AM
    does this argument still exist?
    "-Xallow-kotlin-package"
    d
    • 2
    • 1
  • v

    Vitali Plagov

    06/29/2022, 12:35 PM
    Just enabled the new K2 compiler in our project. Not a super big project, just a regular back-end API service. But already see the difference in compilation time. 👍 In the

    1.7.0 release video▾

    there’s another flag -
    -Xbackend-threads=4
    . But it doesn’t affect the compilation time regardless of number of threads I specify. Am I doing something wrong or missing?
    compileKotlin {
        kotlinOptions {
            jvmTarget = JavaVersion.VERSION_11
            freeCompilerArgs = ["-Xuse-k2", "-Xbackend-threads=4"]
        }
    }
    d
    u
    • 3
    • 4
  • j

    Jake Woods

    06/30/2022, 4:01 AM
    Does anyone know what
    _η_−1
    means as part of the definition of
    ϕ
    in the kotlin spec least upper bound algorithm? Everything else seems to be defined somewhere in the document but I can’t figure out what the substitution would be for ``_η_−1({out LUB(x_out, y_out), in GLB(x_in, y_in)}`. 🙏
    e
    • 2
    • 3
  • r

    reactormonk

    07/04/2022, 7:26 AM
    I think I'm already hitting the limits of the compiler... Wrapping an API into coroutines:
    suspend fun <ReaderType, ReturnType> registerCallback(listener: (((ReaderType) -> Unit)?) -> Unit, func: (ReaderType) -> ReturnType): ReturnType {
        return suspendCoroutine<ReturnType> { block ->
            listener { btr ->
                block.resume(func(btr))
                listener(null)
            }
        }
    }
    
    val reader = registerCallback(acsBluetoothReaderManager::setOnReaderDetectionListener) { reader ->
      [...]
      reader
    }
    gives me
    java.lang.ClassCastException: org.reactormonk.debugapplication.BluetoothSupportKt$registerCallback$2$1 cannot be cast to com.acs.bluetooth.BluetoothReaderManager$OnReaderDetectionListener
            at org.reactormonk.debugapplication.BluetoothNFCActivity$onCreate$1$reader$1.invoke(BluetoothNFC.kt:72)
    Compiles fine though. This is the interface:
    public void setOnReaderDetectionListener(BluetoothReaderManager.OnReaderDetectionListener listener) {
            this.b = listener;
        }
    
        public interface OnReaderDetectionListener {
            void onReaderDetection(BluetoothReader var1);
        }
    g
    • 2
    • 6
  • f

    fwcd

    07/06/2022, 11:31 AM
    Hey everyone 👋 I'd be interested in experimenting in with the new analysis API, are the JARs for the new standalone analysis API already hosted on some Maven repo?
    r
    d
    +2
    • 5
    • 16
  • d

    dmitriy.novozhilov

    07/06/2022, 2:04 PM
    Fork of previous thread
    y
    r
    • 3
    • 22
Powered by Linen
Title
d

dmitriy.novozhilov

07/06/2022, 2:04 PM
Fork of previous thread
https://kotlinlang.slack.com/archives/C7L3JB43G/p1657116094111869?thread_ts=1657107084.592159&amp;cid=C7L3JB43G
y

Youssef Shoaib [MOD]

07/06/2022, 2:07 PM
If that idea is a no-go, could we have a hook into `FirCallResolver`to provide our own `Candidate`s? I think it can achieve the same goal of turning red code green by providing a valid candidate. Or, how about a
doAnalysis
-style hook that just allows a plugin to go wild and resolve an expression from the start however it wants?
d

dmitriy.novozhilov

07/06/2022, 2:09 PM
Call can be completed with some outer call
fun <K> materialize(): K = null!!
fun <T> id(x: T): T = x
fun takeInt(x: Int) {}

fun test() {
    takeInt(id(materialize()))
}
In this example
materialize
and
id
will be completed only during completion of call
takeInt
So if you change candidate (and, potentially, return type) of inner call (
materialize
) then it require to reanalyze all calls in chain, because with new type of argument some other functions for outer calls can be applicable
could we have a hook into
FirCallResolver
to provide our own
Candidate
This is also is a bad idea, because call resolution is already extremely complicated (did you read that part of specification?), and providing custom rules to it from plugins will blow everybody minds (compiler devs, plugin devs and regular users)
But you can provide new declarations with
FirDeclarationGenerationExtension
, why it's not enough for you?
Or, how about a
doAnalysis
-style hook that just allows a plugin to go wild and resolve an expression from the start however it wants?
With this approach Kotlin with such plugin won't be Kotlin anymore, because there are no guarantees that plugin will do everything according to specification
y

Youssef Shoaib [MOD]

07/06/2022, 2:55 PM
Well, let's make this concrete because I think maybe my use case just so happens to not maybe fall into some of those pitfalls. I'm trying to design a DI plugin that, whenever there's a missing context receiver, it provides it based on some annotated function. (I'm aware that
addNewImplicitReceivers
exists, and in fact that's what arrow-inject uses, but I wanted something that wouldn't require the user to explicitly say what receivers they want) From my observations, when there's multiple candidates that can work, except that both have some missing context receiver, I got a
ConeAmbiguityError
so already there isn't one candidate that can work, and so my plugin just helps choose one of them, while if there's only one candidate that can work (but is missing a context receiver), I got an
InapplicableCandidateError
, and so my plugin then doesn't change the candidate to a different function, but simply allows the candidate to be considered applicable because a new context receiver gets added into the tower data. In the case of the `materialize`example (which is actually quite apt because it is similar to a function I've already tested) the return type of materialize would either be determined by explicit type arguments, by the type that id expects, or if there's no other type hints at all, then by the context receiver it is missing (i.e. if materialize had a
context(MyWrapper<K>)
and there's only one `MyWrapper`that the plugin knows about with some concrete type). The return type of materialize then changes in 2 cases: • If it had no type hints, then now it has a return type, which I think is considered okay • If it knows what type it needed to be, then materialize's return type is either that required type or some subtype of it, but if it is a subtype then I'd and takeInt should still be satisfied (keep in mind that if
takeInt
had 2 overloads with one of them taking a subtype of the other then already it would be trying to choose which overload wins based on the argument) I hope that this makes some sense, hopefully. I'm on mobile rn so it's kinda difficult to provide actual code. Thank you, by the way, because this has helped open my eyes to some incorrect assumptions that I had about the compiler.
r

raulraja

07/06/2022, 5:19 PM
@dmitriy.novozhilov This is somewhat of the same use case we have in arrow-inject where we need to provide our own code to resolve and complete a call given a set of candidates. @Youssef Shoaib [MOD] we are doing something very similar or the same plugin at https://github.com/arrow-kt/arrow-inject/blob/e5a7be736eb01e5eab014d9b36eef2e61cf2[…]er/plugin/fir/resolution/resolver/ProofResolutionStageRunner.kt
https://github.com/arrow-kt/arrow-inject/tree/e5a7be736eb01e5eab014d9b36eef2e61cf2[…]arrow-inject-compiler-plugin/src/testData/box/context-receivers
y

Youssef Shoaib [MOD]

07/06/2022, 5:35 PM
@raulraja I'm really glad you saw this thread as I've been meaning to ask about arrow-inject. 1. How do you actually run your ProofResolutionStageRunner? I haven't looked around your codebase in an IDE so sorry if it's too obvious. I couldn't figure out how to run one myself, couldn't really find a hook anywhere 2. I'm basically trying to do the same general idea as arrow-inject, but without the need for
context<Foo<Int>>()
for instance (i.e. I want the context to be available without the user explicitly writing out the type so that e.g. in your polymorphic provider test I could call a function that expects a
Foo<Int>
in its context and that would be resolved without requiring a
context<Foo<Int>>()
right before the call). The reason behind this is that I want to extensively use contexts with generics without having to type out what generic type it needs (e.g. if I have functions that take `Foo<String> Foo<Int>`or even a
Foo<Foo<Foo<List<Any>>>>
I would like all of those function calls to be resolved without any explicit types).
r

raulraja

07/06/2022, 5:38 PM
I'm interested in seeing an example of what you mean, seems what you are doing is adding context receivers automatically where needed. At some point though you need to set what your instances for those types are and the final call needs nested
with
. We have replicated more or less what the ResolutionStageRunner does in the compiler to have the ability to resolve a fake call given a set of candidates.
Also overall I'm hoping Kotlin provides at some point a way to inject or make it easier to make concrete instances without a set of nested `run`or nested
with
y

Youssef Shoaib [MOD]

07/06/2022, 5:50 PM
Basically what I mean is this:
@Provider internal fun intProvider(): Int = 42
@Provider internal fun stringProvider(): String = "hello world"
data class Foo<A>(val n: A)

context(A)
@Provider internal fun <A> fooProvider(): Foo<A> = Foo(this@A)

context(Foo<Int>) fun needsInt() = TODO()
context(Foo<String>) fun needsString() = TODO()

fun box(): String {
  needsInt() //in FIR, it'll have a call to fooProvider as its first contextReceiverArgument, and in turn that call to fooProvider has a call to intProvider as its first contextReceiverArgument (or could be done in IR, doesn't matter)
  needsString() // should have first CR argument as call to fooProvider, which has first CR argument as call to stringProvider 
}
I want that to compile with no errors, and on the two
needsX
calls, the context receiver should basically be a new Foo instance with the Int/String inside of it (which is what to be expected from the providers). With arrow-inject right now I'd need to add the apt calls of arrow's
context<>()
function, but that feels redundant to me.
r

raulraja

07/06/2022, 6:42 PM
I see, this is even more implicit but can work in the same way. We have in IR both the calls to
contextual
but also the error expression types resulting from
addNewImplicitReceivers
when the fir call has errors. https://github.com/arrow-kt/arrow-inject/blob/e5a7be736eb01e5eab014d9b36eef2e61cf2[…]/fir/resolution/contexts/ContextProvidersResolutionExtension.kt
Right now we are just looking at the type args of the
contextOf
function but could just look at the error types in resolution to look up the providers.
y

Youssef Shoaib [MOD]

07/06/2022, 7:03 PM
Yes but how would you then resolve those errors, as in, how would you change the callee reference then to not be an error-signalling one. What it sounds like is that FIR most likely won't support such an API. I guess you could just suppress all context-related errors, but that doesn't seem like a good idea to me. Especially because, you could have 2 overloads where only one is valid based on a provider e.g.:
context(Int) fun foo() = TODO()
context(String) fun foo() = TODO()
@Provider internal fun intProvider(): Int = 42

fun main() {
  foo() // should run the one expecting Int
}
Suppressing the errors in this case won't make resolution run correctly here, and if there's no way to alter the callee reference (at least no officially supported API) then such a case won't be possible. I think that an API to support something like that should exist therefore.
r

raulraja

07/06/2022, 7:25 PM
Are you currently using
override fun addNewImplicitReceivers(functionCall: FirFunctionCall): List<ConeKotlinType>
? I'm speculating that when you add the expected types there then the function call should resolve fine because that is added prior to resolving calls.
Resolution then in our case proceeds fine to IR but it gets to IR with some error types that still need to be replaced for the proper nested with and expressions needed around the call https://github.com/arrow-kt/arrow-inject/blob/e5a7be736e/arrow-inject-compiler-plu[…]ow/inject/compiler/plugin/ir/ProofsIrContextReceiversCodegen.kt
y

Youssef Shoaib [MOD]

07/06/2022, 7:32 PM
addNewImplicitReceivers
is actually called after the call is completely resolved. Obviously that doesn't matter for arrow's case, but in my case I basically get the
BodyResolveComponents
using a hack (I register a custom
FirSessionComponent
like this to get access to all the Body Resolve Components then I filter for the one I want) and then inside
addNewImplicitReceivers
I figure out the missing context receiver types, find the right providers for them, add them to the towerDataContext, call the expressions transformer (which can be accessed thru BodyResolveComponents), and then remove them from towerDataContext. Finally I use replaceContextReceiverArguments to make them function calls instead (but I could use the arrow approach in IR instead, doesn't matter too much). And so, I need BodyResolveComponents inside
addNewImplicitReceivers
so that I can access the transformer (or alternatively, I could use the callResolver and callCompleter, but both of which are still inside BodyResolveComponents). I could create my own BodyResolveComponents, but they'll be missing all the surrounding receivers for instance since I won't have access to the real towerDataContext.
d

dmitriy.novozhilov

07/07/2022, 7:34 AM
You want to do really scary things. For me it looks like you are trying to make implicits from Scala from context receivers. And we put all our effort to not to do it during design of context, because implicits can easily transform code to a not understandable mess Generally we don't want to allow plugins to interfere with call resolution process (because of reasons I described above), but we can probably reconsider it if we have really good usecases which can not be achieved with existing API
r

raulraja

07/07/2022, 11:51 AM
In our case even when the injection is explicit to the type we want to inject we need a form of call resolution to select the right provider for the call. There can be more than one provided with compatible types due to polymorphism and generics. The most specific one has to be chosen. I think in general compile time DI requires implicit resolution and the plugins attempt to implement a form of DI. People will use DI whether we think it's a good idea or not because the places they are at. There is a fairly large amount of people on Android using Dagger. Dagger codegens and generates a lot of unnecessary code where it could all be done at compile time. Trying to leverage context receivers as much as we can we still have the need to resolve them at some point. I'm not familiar with compile time DI that does not look a bit like implicits at least in resolution / injection but happy to explores new ways if there is a better one than this.
d

dmitriy.novozhilov

07/07/2022, 12:48 PM
I also didn't explore compile time DI methods yet I plan to do it sometime in future, but definitely not in the nearest one
View count: 5