Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (Cyborg)
  • No Skin
Collapse
Brand Logo

CIRCLE WITH A DOT

  1. Home
  2. Uncategorized
  3. I landed some performance improvements for the Swift type checker recently, and I'm currently finishing up the next set of changes which I hope to merge soon.

I landed some performance improvements for the Swift type checker recently, and I'm currently finishing up the next set of changes which I hope to merge soon.

Scheduled Pinned Locked Moved Uncategorized
17 Posts 7 Posters 26 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • slava@mathstodon.xyzS slava@mathstodon.xyz

    In binding inference, we had an existing optimization that would consider types that have no proper subtypes. For example, if you have

    $T0 conv Int

    Then in fact we know that Int (like almost all structs, and all user-defined structs) has no proper subtypes, that is, types that convert to it. So we can always bind $T0 to Int in this case.

    I generalized this idea further. Suppose you instead have:

    Int conv $T0

    You can't apply the same optimization here, and just say that $T0 is Int. In Swift, _every_ type has supertypes; those are an optional wrapping the type, the existential types to which this type conforms, and the special standard library AnyHashable type, which is a supertype of every concrete type that conforms to Hashable.

    slava@mathstodon.xyzS This user is from outside of this forum
    slava@mathstodon.xyzS This user is from outside of this forum
    slava@mathstodon.xyz
    wrote last edited by
    #8

    But suppose you also have a conformance constraint, and you know that $T0 must conform to some protocol, say BinaryInteger:

    Int conv $T0
    $T0 conforms BinaryInteger

    Well, existential types cannot conform to protocols in Swift, so we can rule out the possibility that $T0 is existential. It might still be Optional<Int> or AnyHashable, perhaps, but those don't conform to BinaryInteger either.

    So now, we can "prove" that $T0's domain contains exactly one type, and so we can bind $T0 to Int.

    What if you end up in a situation where you're looking at this?

    Int conv $T0
    $T0 conforms Sequence

    Well, Int doesn't conform to Sequence, and neither does Optional<Int> or AnyHashable, so we've made a conflicting set of overload choices; we just haven't realized it yet, because the domain of $T0 is the empty set.

    Now we _do_ realize it, and bind Int to $T0 anyway; this fails the conformance constraint, and in some cases, it fails it much sooner than it would have otherwise, reducing wasted time spent in dead ends.

    slava@mathstodon.xyzS jrose@social.belkadan.comJ 2 Replies Last reply
    0
    • slava@mathstodon.xyzS slava@mathstodon.xyz

      But suppose you also have a conformance constraint, and you know that $T0 must conform to some protocol, say BinaryInteger:

      Int conv $T0
      $T0 conforms BinaryInteger

      Well, existential types cannot conform to protocols in Swift, so we can rule out the possibility that $T0 is existential. It might still be Optional<Int> or AnyHashable, perhaps, but those don't conform to BinaryInteger either.

      So now, we can "prove" that $T0's domain contains exactly one type, and so we can bind $T0 to Int.

      What if you end up in a situation where you're looking at this?

      Int conv $T0
      $T0 conforms Sequence

      Well, Int doesn't conform to Sequence, and neither does Optional<Int> or AnyHashable, so we've made a conflicting set of overload choices; we just haven't realized it yet, because the domain of $T0 is the empty set.

      Now we _do_ realize it, and bind Int to $T0 anyway; this fails the conformance constraint, and in some cases, it fails it much sooner than it would have otherwise, reducing wasted time spent in dead ends.

      slava@mathstodon.xyzS This user is from outside of this forum
      slava@mathstodon.xyzS This user is from outside of this forum
      slava@mathstodon.xyz
      wrote last edited by
      #9

      There are more tricks possible by considering multiple adjacent constraints.

      An existing optimization would compute the join of two types (the least common supertype) in a situation like this:

      Foo conv $T0
      Bar conv $T0

      The implementation of joins() was old and incomplete though and it missed many common situations. I rewrote it to model Swift's subtyping rules faithfully. I got it to compute meets. Unlike joins, where all types are subtypes of the universal Any type, the meet can be empty. For example, suppose that Foo and Bar are classes:

      $T0 conv Foo
      $T0 conv Bar

      By the previous rules, we cannot bind $T0 to Foo or Bar, because Foo and Bar might have proper subtypes (one might be a subclass of the other).

      But if neither is a subclass of the other, then $T0's domain is empty, and we can bind $T0 to Foo or Bar at this point, and backtrack.

      There are a few more combinations, for example if you have this:

      Int conv $T0
      $T0 conv Optional<String>

      There is no type for $T0 that is a supertype of Int but also a subtype of Optional<String>.

      slava@mathstodon.xyzS 1 Reply Last reply
      0
      • slava@mathstodon.xyzS slava@mathstodon.xyz

        There are more tricks possible by considering multiple adjacent constraints.

        An existing optimization would compute the join of two types (the least common supertype) in a situation like this:

        Foo conv $T0
        Bar conv $T0

        The implementation of joins() was old and incomplete though and it missed many common situations. I rewrote it to model Swift's subtyping rules faithfully. I got it to compute meets. Unlike joins, where all types are subtypes of the universal Any type, the meet can be empty. For example, suppose that Foo and Bar are classes:

        $T0 conv Foo
        $T0 conv Bar

        By the previous rules, we cannot bind $T0 to Foo or Bar, because Foo and Bar might have proper subtypes (one might be a subclass of the other).

        But if neither is a subclass of the other, then $T0's domain is empty, and we can bind $T0 to Foo or Bar at this point, and backtrack.

        There are a few more combinations, for example if you have this:

        Int conv $T0
        $T0 conv Optional<String>

        There is no type for $T0 that is a supertype of Int but also a subtype of Optional<String>.

        slava@mathstodon.xyzS This user is from outside of this forum
        slava@mathstodon.xyzS This user is from outside of this forum
        slava@mathstodon.xyz
        wrote last edited by
        #10

        I've got a few more things cooking, but that's enough for now. There are more details in the description for my latest PR, which links to the previous PR, which also links to the one before that: https://github.com/swiftlang/swift/pull/87669

        gregtitus@social.coopG ole@chaos.socialO 2 Replies Last reply
        0
        • slava@mathstodon.xyzS slava@mathstodon.xyz

          But suppose you also have a conformance constraint, and you know that $T0 must conform to some protocol, say BinaryInteger:

          Int conv $T0
          $T0 conforms BinaryInteger

          Well, existential types cannot conform to protocols in Swift, so we can rule out the possibility that $T0 is existential. It might still be Optional<Int> or AnyHashable, perhaps, but those don't conform to BinaryInteger either.

          So now, we can "prove" that $T0's domain contains exactly one type, and so we can bind $T0 to Int.

          What if you end up in a situation where you're looking at this?

          Int conv $T0
          $T0 conforms Sequence

          Well, Int doesn't conform to Sequence, and neither does Optional<Int> or AnyHashable, so we've made a conflicting set of overload choices; we just haven't realized it yet, because the domain of $T0 is the empty set.

          Now we _do_ realize it, and bind Int to $T0 anyway; this fails the conformance constraint, and in some cases, it fails it much sooner than it would have otherwise, reducing wasted time spent in dead ends.

          jrose@social.belkadan.comJ This user is from outside of this forum
          jrose@social.belkadan.comJ This user is from outside of this forum
          jrose@social.belkadan.com
          wrote last edited by
          #11

          @slava > Well, existential types cannot conform to protocols in Swift, so we can rule out the possibility that $T0 is existential.

          except the ones that do (Error and @objc protocols). I wouldn’t be surprised if there are more in the future. Hopefully this isn’t a loadbearing part of the optimizations!

          slava@mathstodon.xyzS 1 Reply Last reply
          0
          • slava@mathstodon.xyzS slava@mathstodon.xyz

            I've got a few more things cooking, but that's enough for now. There are more details in the description for my latest PR, which links to the previous PR, which also links to the one before that: https://github.com/swiftlang/swift/pull/87669

            gregtitus@social.coopG This user is from outside of this forum
            gregtitus@social.coopG This user is from outside of this forum
            gregtitus@social.coop
            wrote last edited by
            #12

            @slava I admire how you can explain this type of thing with such clarity.

            mergesort@macaw.socialM 1 Reply Last reply
            0
            • jrose@social.belkadan.comJ jrose@social.belkadan.com

              @slava > Well, existential types cannot conform to protocols in Swift, so we can rule out the possibility that $T0 is existential.

              except the ones that do (Error and @objc protocols). I wouldn’t be surprised if there are more in the future. Hopefully this isn’t a loadbearing part of the optimizations!

              slava@mathstodon.xyzS This user is from outside of this forum
              slava@mathstodon.xyzS This user is from outside of this forum
              slava@mathstodon.xyz
              wrote last edited by
              #13

              @jrose Of course, but we know which protocols are self-conforming, so we skip those. As long as self-conformance remains "opt-in", it will be fine.

              (In one of the cases where I got a speedup from this, the protocol was SIMD which is unlikely to self-conform in the near future :))

              1 Reply Last reply
              0
              • slava@mathstodon.xyzS slava@mathstodon.xyz

                I landed some performance improvements for the Swift type checker recently, and I'm currently finishing up the next set of changes which I hope to merge soon.

                There are two main improvements. The first is a new "disjunction pruning" optimization to help skip impossible overload choices, and the second set of improvements concern implicit conversions and the constraints they generate.

                ferrix@mastodon.onlineF This user is from outside of this forum
                ferrix@mastodon.onlineF This user is from outside of this forum
                ferrix@mastodon.online
                wrote last edited by
                #14

                @slava @joe what do we want? Better performance!

                When do we want it? Optimally soon.

                1 Reply Last reply
                0
                • gregtitus@social.coopG gregtitus@social.coop

                  @slava I admire how you can explain this type of thing with such clarity.

                  mergesort@macaw.socialM This user is from outside of this forum
                  mergesort@macaw.socialM This user is from outside of this forum
                  mergesort@macaw.social
                  wrote last edited by
                  #15

                  @gregtitus @slava This *type* of thing, amirite?

                  1 Reply Last reply
                  0
                  • slava@mathstodon.xyzS slava@mathstodon.xyz

                    I've got a few more things cooking, but that's enough for now. There are more details in the description for my latest PR, which links to the previous PR, which also links to the one before that: https://github.com/swiftlang/swift/pull/87669

                    ole@chaos.socialO This user is from outside of this forum
                    ole@chaos.socialO This user is from outside of this forum
                    ole@chaos.social
                    wrote last edited by
                    #16

                    @slava Thank you for the great explanation! This went right into my notes.

                    1 Reply Last reply
                    0
                    • slava@mathstodon.xyzS slava@mathstodon.xyz

                      I landed some performance improvements for the Swift type checker recently, and I'm currently finishing up the next set of changes which I hope to merge soon.

                      There are two main improvements. The first is a new "disjunction pruning" optimization to help skip impossible overload choices, and the second set of improvements concern implicit conversions and the constraints they generate.

                      madcoder@infosec.exchangeM This user is from outside of this forum
                      madcoder@infosec.exchangeM This user is from outside of this forum
                      madcoder@infosec.exchange
                      wrote last edited by
                      #17

                      @slava color me naive but do we cache the precious result of a type checker when it was super expensive? It still doesn’t help you with the first time but…

                      1 Reply Last reply
                      1
                      0
                      • R relay@relay.infosec.exchange shared this topic
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups