https://kotlinlang.org logo
Join SlackCommunities
Powered by
# pattern-matching
  • m

    mattmoore

    06/26/2020, 3:25 AM
    This totally works! There's a bug that I'll describe tomorrow. But I was able to (in addition to running tests) actually run this against a fresh Kotlin project.
    šŸŽ‰ 2
    šŸ˜ 3
    r
    s
    b
    • 4
    • 21
  • m

    mattmoore

    06/27/2020, 4:54 PM
    This was the bug I was talking about:
    Copy code
    data class Person(val firstName: String, val lastName: String)
    
    fun main(args: Array<String>) {
      val person = Person("Matt", "Moore")
      val result = when (person) {
        Person(capturedFirstName, _) -> capturedFirstName
        else -> "Not matched"
      }
    
      println(result)
    }
    Yields:
    Copy code
    e: java.lang.ClassCastException: org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor cannot be cast to org.jetbrains.kotlin.descriptors.PropertyDescriptor
    If I pull
    val person...
    out of
    main
    , then it works:
    Copy code
    data class Person(val firstName: String, val lastName: String)
    val person = Person("Matt", "Moore")
    
    fun main(args: Array<String>) {
      val result = when (person) {
        Person(capturedFirstName, _) -> capturedFirstName
        else -> "Not matched"
      }
    
      println(result)
    }
    I'm finally able to get back to this now.
  • m

    mattmoore

    06/27/2020, 5:25 PM
    @shikasd Merged in your latest, as it's passing for me locally. I also moved all the plugin entry code from the test over to
    PatternMatchingPlugin.kt
    file. I'm taking a look now through all the code and experimenting with it.
  • m

    mattmoore

    06/27/2020, 5:25 PM
    Thanks for your help on this! Much appreciated.
  • s

    shikasd

    06/27/2020, 5:27 PM
    No worries, happy to help :) I can probably clean it up later, as currently it is a mess to just make it work
  • m

    mattmoore

    06/27/2020, 5:28 PM
    Also, your recent changes fixed the issue I just mentioned, so it's working within
    main
    now.
    šŸ‘ 2
  • m

    mattmoore

    06/27/2020, 5:29 PM
    No worries. My philosophy is to get it working first, then clean up and refactor after šŸ™‚
  • s

    shikasd

    06/27/2020, 5:31 PM
    Sure :)
  • s

    shikasd

    06/29/2020, 2:35 PM
    Heyo, I was experimenting with smarter matching yesterday, trying to make it work for sealed classes Here we have a problem, that the call cannot be associated with the variable in the when expr anymore, as it could be of the wrong type šŸ™‚ I think now it is time to go into IR wonderland. My plan here is to mark all expressions that look like pattern matching and then find them in IR to replace the calls. Idea is to have
    Person(_, capturedVariable)
    to be converted into
    is Person -> { val captured = capturedVariable }
    Not sure for how it'll go, just wanted to share things I am looking at.
  • r

    raulraja

    06/29/2020, 10:26 PM
    we were using
    case
    as marker to replace in the tree
  • r

    raulraja

    06/29/2020, 10:26 PM
    just a synth stub
  • s

    shikasd

    06/30/2020, 10:29 AM
    yeah, that's how I find them in IR šŸ™‚ btw, did you test meta with latest master where they fixed IR?
  • r

    raulraja

    06/30/2020, 11:39 AM
    @Rachel ^^^
  • r

    raulraja

    06/30/2020, 11:40 AM
    @Rachel is taking care of the update to 1.4 and IR, @shikasd do you have a link to the issue or place where this is fixed? no worries if not, just curious
  • r

    Rachel

    06/30/2020, 11:43 AM
    šŸ™Œ Right! I'll try it again because it seems it's stable now after a mix of changes between latest EAP and DEV version. I'll let you know the results asap
    šŸ‘ 2
    r
    • 2
    • 1
  • r

    Rachel

    06/30/2020, 2:27 PM
    @shikasd, It's still failing for us However, I'm not sure if it isn't fixed or I'm not upgrading Arrow Meta properly for latest DEV version or latest EAP version because there are a lot of API changes I pushed 2 branches in case you want to check it Both of them have just an additional commit on
    master
    branch with all the changes to use latest versions: - Branch
    upgrade-to-1.4-M3
    for latest EAP
    1.4-M3-eap-180
    - Branch
    upgrade-to-1.4-dev
    for latest DEV
    1.4.20-dev-1427-233
    s
    • 2
    • 7
  • m

    mattmoore

    06/30/2020, 7:38 PM
    @shikasd Awesome work so far! One thought I had was on the "marking" of the expression to match. So as @raulraja pointed out, we've got
    case
    synthetic to act as a marker. In the current iteration, it's looking at
    when
    subject, but we would also need to handle the expression when it's not a
    when
    subject or even outside
    when
    entirely. For example:
    Copy code
    val matt = Person("Matt", "Moore")
    val Person(_, lastName) = matt
    Another example would be for matching on lists (though that's not quite in scope just yet, as there's more stuff to solve there). I'll be able to experiment more with this tonight. Of course, I'm still new to the internal APIs so having your help, Raul's help, and everyone else on that has been a tremendous boost to this effort. So thank you for that! šŸ™‚ If I'm able to figure out how to generalize the current version without
    when
    expressly (so it'll work in more general cases) I'll push some code up. Unless you beat me to it šŸ˜‰ Thanks @Rachel for looking into 1.4. I'm very eager to see 1.4 be finally ready, as I'm sure all of you are as well šŸ™‚
    šŸ™Œ 2
    s
    • 2
    • 3
  • s

    shikasd

    06/30/2020, 8:05 PM
    Btw, I heard that 1.4 will be released without IR by default and they are pushing it to 1.4.20
    šŸ‘ 3
    m
    • 2
    • 2
  • r

    raulraja

    07/01/2020, 11:11 PM
    kudos on the talks!
  • r

    raulraja

    07/01/2020, 11:12 PM
    they are awesome!
  • s

    shikasd

    07/02/2020, 12:07 AM
    are they available somewhere?
  • j

    julian

    07/02/2020, 12:07 AM
    The London Kotlin UG talk? I think the moderator said it would be available on the group's YouTube channel tomorrow?
  • m

    mattmoore

    07/02/2020, 3:01 AM

    https://www.youtube.com/watch?v=Blj-7SGYUnE&amp;feature=youtu.beā–¾

  • m

    mattmoore

    07/02/2020, 3:03 AM
    Thanks everyone! I hoped it turned out ok. Excited to keep pushing this forward. I’m off for the next few days and will be working more on this over the weekend.
    🤘 9
    m
    • 2
    • 1
  • s

    shikasd

    07/08/2020, 12:42 AM
    heyo, I pushed it a bit further last two evenings and got basic support for sealed classes working in this PR for now only it supports data class with one parameter, because I need to pass the info about index of parameter to IR level somehow. (Problem for tomorrow) I also had to rewrite some parts of analysis. Now we go through contents of all files and check when expressions directly instead of relying on diagnostics to detect them. And the last change, we also have a
    todo
    property in the prelude which serves as a placeholder to complete calls in PSI. (also merged master, so sorry for a bit messy changeset)
    m
    r
    • 3
    • 19
  • m

    mattmoore

    07/09/2020, 11:00 PM
    @shikasd I added the IDEA plugin portion to hook up the existing pattern matching code (well, part of it is pushed). I'm doing some refactors to make things a little more plug-n-play between the CLI and IDEA. Should have that pushed up fairly soonish.
    s
    • 2
    • 1
  • m

    mattmoore

    07/09/2020, 11:01 PM
    Great work so far on everything! You've really helped move this forward more! šŸ™‚
    ā¤ļø 1
  • m

    mattmoore

    11/17/2020, 5:49 PM
    I wanted to thank all those who helped with this earlier this year. I learned a lot from that experience! I wanted to share a quick status update: It’s been a while since I’ve been able to come back to this. But I have started back on it again with Kotlin 1.4 and Meta 0.11.0. Started working through the code we have so far and at a high level there are 2 things I’m working towards in spare time: 1. Obviously, the new compiler changed things. I’m looking at the latest compiler source (and latest Meta) to get a sense for deprecations. I’ve made some decent progress on this, but it’s still heavily in progress. 2. Some of the code had gotten a little dependent on
    when
    - but we want matching to be decoupled from that. So I’m inverting the process to start with the
    case
    synthetic as the starting point, and attempting to only traverse up or down the tree if it’s necessary to do so - but currently I don’t think it will be necessary. This would ensure that
    case
    is adaptable outside of
    when
    . I’m not sure precisely when I’ll have code fully ready to share as this year has gotten incredibly busy. But I will have some more time freeing up in the next few weeks to devote more time to this and hopefully have an initial prototype working perhaps some time this year/early next on the latest Kotlin/Meta. I’ll probably be in the #arrow-meta and #compiler channel as well asking questions there about new compiler design at some point.
    šŸ‘ 2
  • d

    dephinera

    02/02/2021, 11:58 AM
    Are there any limitations in Kotlin, that do not allow multiple values in
    when
    like the ones in Swift?
    Copy code
    let point = CGPoint(x: 7, y: 0)
    switch (point.x, point.y) {
      case (0,0): print("On the origin!")
      case (0,_): print("x=0: on Y-axis!")
      case (_,0): print("y=0: on X-axis!")
      case (let x, let y) where x == y: print("On y=x")
      default: print("Quite a random point here.")
    }
    AFAIK Swift language supports tuples and I suppose the construct here does a tuple comparison, but I don't see a reason why this shouldn't be just a syntax sugar for multiple if-elses or a when without a parameter and comparisons in each branch. One thing that I think might be an issue is if we want to match types, where we'd have something like this:
    Copy code
    sealed class A { 
       class X : A()
       class Y : A()
    }
    sealed class B { 
        class X : B()
        class Y : B()
    }
    And then I guess there should be more syntax introduced, like this
    Copy code
    ...
    fun foo(a: A, b: B) = when (a, b) {
        (is A.X, is B.X) -> TODO()
        (is A.Y, is B.Y) -> TODO()   
    }
    Or if we want to match multiple types
    Copy code
    ...
    fun foo(a: A, b: B) = when (a, b) {
        (is A.X or is A.Y, is B.X) -> TODO()
        (is A.Y or is A.X, is B.Y) -> TODO()   
    }
    // or
    fun foo(a: A, b: B) = when (a, b) {
        (is (A.X | is A.Y), is B.X) -> TODO()
        (is (A.Y | is A.X), is B.Y) -> TODO()   
    }
    I hope I explained the idea well enough. So are there any limitations to make this possible? If not - should we expect something like this in the future? Do you think it's something that we actually need?
    r
    • 2
    • 1
  • m

    mattmoore

    03/11/2021, 4:31 PM
    So I’ve been looking into the 1.4 changes and regarding
    _
    and here’s where I’m at so far. I’ve started moving pattern matching back to generalized
    case
    expression as the resolution starting-point. From there it will check to see the context it’s in (
    where
    expression,
    if
    expression, etc…) and then do the tree transform later in IR. However, with 1.4 of the Kotlin compiler, after I’ve suppressed the ā€œunresolvedā€ errors, I’m now receiving a ā€œunbound symbols not allowedā€ error. Tracing this back I see this is where a check is done for
    context.symbolTable.allUnbound
    https://github.com/JetBrains/kotlin/blob/v1.4.10/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt#L96 What would be the appropriate way to bind
    _
    to another semantically valid symbol? I’m already using
    BindingContext
    to do a
    record
    (which then shows up in the binding context). Since the file above is called
    Psi2IrTranslator
    and the function is
    generateModuleFragment
    I’m guessing I need to either generate IR or map this to the IR that for the semantically valid symbols that I’m attempting to reference with
    _
    . In this scenario, I want the symbol
    _
    to be bound to a
    KtNameReferenceExpression
    , as it would refer to a data class argument.
    r
    • 2
    • 5