@@ -623,36 +623,109 @@ func _trueAfterDiagnostics() -> Builtin.Int1 {
623
623
624
624
/// Returns the dynamic type of a value.
625
625
///
626
- /// - Parameter of: The value to take the dynamic type of.
627
- /// - Returns: The dynamic type, which will be a value of metatype type.
628
- ///
629
- /// - Remark: If the parameter is statically of a protocol or protocol
630
- /// composition type, the result will be an *existential metatype*
631
- /// (`P.Type` for a protocol `P`), and will represent the type of the value
632
- /// inside the existential container with the same protocol conformances
633
- /// as the value. Otherwise, the result will be a *concrete metatype*
634
- /// (`T.Type` for a non-protocol type `T`, or `P.Protocol` for a protocol
635
- /// `P`). Normally, this will do what you mean, but one wart to be aware
636
- /// of is when you use `type(of:)` in a generic context with a type
637
- /// parameter bound to a protocol type:
638
- ///
639
- /// ```
640
- /// func foo<T>(x: T) -> T.Type {
641
- /// return type(of: x)
642
- /// }
643
- /// protocol P {}
644
- /// func bar(x: P) {
645
- /// foo(x: x) // Call foo with T == P
646
- /// }
647
- /// ```
648
- ///
649
- /// since the call to `type(of:)` inside `foo` only sees `T` as a concrete
650
- /// type, foo will end up returning `P.self` instead of the dynamic type
651
- /// inside `x`. This can be worked around by writing `type(of: x as Any)`
652
- /// to get the dynamic type inside `x` as an `Any.Type`.
626
+ /// You can use the `type(of:)` function to find the dynamic type of a value,
627
+ /// particularly when the dynamic type is different from the static type. The
628
+ /// *static type* of a value is the known, compile-time type of the value. The
629
+ /// *dynamic type* of a value is the value's actual type at run-time, which
630
+ /// may be nested inside its concrete type.
631
+ ///
632
+ /// In the following code, the `count` variable has the same static and dynamic
633
+ /// type: `Int`. When `count` is passed to the `printInfo(_:)` function,
634
+ /// however, the `value` parameter has a static type of `Any`, the type
635
+ /// declared for the parameter, and a dynamic type of `Int`.
636
+ ///
637
+ /// func printInfo(_ value: Any) {
638
+ /// let type = type(of: value)
639
+ /// print("'\(value)' of type '\(type)'")
640
+ /// }
641
+ ///
642
+ /// let count: Int = 5
643
+ /// printInfo(count)
644
+ /// // '5' of type 'Int'
645
+ ///
646
+ /// The dynamic type returned from `type(of:)` is a *concrete metatype*
647
+ /// (`T.Type`) for a class, structure, enumeration, or other non-protocol type
648
+ /// `T`, or an *existential metatype* (`P.Type`) for a protocol or protocol
649
+ /// composition `P`. When the static type of the value passed to `type(of:)`
650
+ /// is constrained to a class or protocol, you can use that metatype to access
651
+ /// initializers or other static members of the class or protocol.
652
+ ///
653
+ /// For example, the parameter passed as `value` to the `printSmileyInfo(_:)`
654
+ /// function in the example below is an instance of the `Smiley` class or one
655
+ /// of its subclasses. The function uses `type(of:)` to find the dynamic type
656
+ /// of `value`, which itself is an instance of the `Smiley.Type` metatype.
657
+ ///
658
+ /// class Smiley {
659
+ /// class var text: String {
660
+ /// return ":)"
661
+ /// }
662
+ /// }
663
+ ///
664
+ /// class EmojiSmiley : Smiley {
665
+ /// override class var text: String {
666
+ /// return "😀"
667
+ /// }
668
+ /// }
669
+ ///
670
+ /// func printSmileyInfo(_ value: Smiley) {
671
+ /// let smileyType = type(of: value)
672
+ /// print("Smile!", smileyType.text)
673
+ /// }
674
+ ///
675
+ /// let emojiSmiley = EmojiSmiley()
676
+ /// printSmileyInfo(emojiSmiley)
677
+ /// // Smile! 😀
678
+ ///
679
+ /// In this example, accessing the `text` property of the `smileyType` metatype
680
+ /// retrieves the overriden value from the `EmojiSmiley` subclass, instead of
681
+ /// the `Smiley` class's original definition.
682
+ ///
683
+ /// Normally, you don't need to be aware of the difference between concrete and
684
+ /// existential metatypes, but calling `type(of:)` can yield unexpected
685
+ /// results in a generic context with a type parameter bound to a protocol. In
686
+ /// a case like this, where a generic parameter `T` is bound to a protocol
687
+ /// `P`, the type parameter is not statically known to be a protocol type in
688
+ /// the body of the generic function, so `type(of:)` can only produce the
689
+ /// concrete metatype `P.Protocol`.
690
+ ///
691
+ /// The following example defines a `printGenericInfo(_:)` function that takes
692
+ /// a generic parameter and declares the `String` type's conformance to a new
693
+ /// protocol `P`. When `printGenericInfo(_:)` is called with a string that has
694
+ /// `P` as its static type, the call to `type(of:)` returns `P.self` instead
695
+ /// of the dynamic type inside the parameter, `String.self`.
696
+ ///
697
+ /// func printGenericInfo<T>(_ value: T) {
698
+ /// let type = type(of: value)
699
+ /// print("'\(value)' of type '\(type)'")
700
+ /// }
701
+ ///
702
+ /// protocol P {}
703
+ /// extension String: P {}
704
+ ///
705
+ /// let stringAsP: P = "Hello!"
706
+ /// printGenericInfo(stringAsP)
707
+ /// // 'Hello!' of type 'P'
708
+ ///
709
+ /// This unexpected result occurs because the call to `type(of: value)` inside
710
+ /// `printGenericInfo(_:)` must return a metatype that is an instance of
711
+ /// `T.Type`, but `String.self` (the expected dynamic type) is not an instance
712
+ /// of `P.Type` (the concrete metatype of `value`. To get the dynamic type
713
+ /// inside `value` in this generic context, cast the parameter to `Any` when
714
+ /// calling `type(of:)`.
715
+ ///
716
+ /// func betterPrintGenericInfo<T>(_ value: T) {
717
+ /// let type = type(of: value as Any)
718
+ /// print("'\(value)' of type '\(type)'")
719
+ /// }
720
+ ///
721
+ /// betterPrintGenericInfo(stringAsP)
722
+ /// // 'Hello!' of type 'String'
723
+ ///
724
+ /// - Parameter value: The value to find the dynamic type of.
725
+ /// - Returns: The dynamic type, which is a value of metatype type.
653
726
@_transparent
654
727
@_semantics ( " typechecker.type(of:) " )
655
- public func type< Type , Metatype> ( of: Type ) -> Metatype {
728
+ public func type< T , Metatype> ( of value : T ) -> Metatype {
656
729
// This implementation is never used, since calls to `Swift.type(of:)` are
657
730
// resolved as a special case by the type checker.
658
731
Builtin . staticReport ( _trueAfterDiagnostics ( ) , true . _value,
@@ -661,73 +734,91 @@ public func type<Type, Metatype>(of: Type) -> Metatype {
661
734
Builtin . unreachable ( )
662
735
}
663
736
664
- /// Allows a nonescaping closure to temporarily be used as if it were
665
- /// allowed to escape.
666
- ///
667
- /// This is useful when you need to pass a closure to an API that can't
668
- /// statically guarantee the closure won't escape when used in a way that
669
- /// won't allow it to escape in practice, such as in a lazy collection
670
- /// view:
671
- ///
672
- /// ```
673
- /// func allValues(in array: [Int], matchPredicate: (Int) -> Bool) -> Bool {
674
- /// // Error because `lazy.filter` may escape the closure if the `lazy`
675
- /// // collection is persisted; however, in this case, we discard the
676
- /// // lazy collection immediately before returning.
677
- /// return array.lazy.filter { !matchPredicate($0) }.isEmpty
678
- /// }
679
- /// ```
680
- ///
681
- /// or with `async`:
682
- ///
683
- /// ```
684
- /// func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void,
685
- /// on queue: DispatchQueue) {
686
- /// // Error: `async` normally escapes the closure, but in this case
687
- /// // we explicitly barrier before the closure would escape
688
- /// queue.async(f)
689
- /// queue.async(g)
690
- /// queue.sync(flags: .barrier) {}
691
- /// }
692
- /// ```
693
- ///
694
- /// `withoutActuallyEscaping` provides a temporarily-escapable copy of the
695
- /// closure that can be used in these situations:
696
- ///
697
- /// ```
698
- /// func allValues(in array: [Int], matchPredicate: (Int) -> Bool) -> Bool {
699
- /// return withoutActuallyEscaping(matchPredicate) { escapablePredicate in
700
- /// array.lazy.filter { !escapableMatchPredicate($0) }.isEmpty
701
- /// }
702
- /// }
703
- ///
704
- /// func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void,
705
- /// on queue: DispatchQueue) {
706
- /// withoutActuallyEscaping(f) { escapableF in
707
- /// withoutActuallyEscaping(g) { escapableG in
708
- /// queue.async(escapableF)
709
- /// queue.async(escapableG)
710
- /// queue.sync(flags: .barrier) {}
737
+ /// Allows a nonescaping closure to temporarily be used as if it were allowed
738
+ /// to escape.
739
+ ///
740
+ /// You can use this function to call an API that takes an escaping closure in
741
+ /// a way that doesn't allow the closure to escape in practice. The examples
742
+ /// below demonstrate how to use `withoutActuallyEscaping(_:do:)` in
743
+ /// conjunction with two common APIs that use escaping closures: lazy
744
+ /// collection views and asynchronous operations.
745
+ ///
746
+ /// The following code declares an `allValues(in:match:)` function that checks
747
+ /// whether all the elements in an array match a predicate. The function won't
748
+ /// compile as written, because a lazy collection's `filter(_:)` method
749
+ /// requires an escaping closure. The lazy collection isn't persisted, so the
750
+ /// `predicate` closure won't actually escape the body of the function, but
751
+ /// even so it can't be used in this way.
752
+ ///
753
+ /// func allValues(in array: [Int], match predicate: (Int) -> Bool) -> Bool {
754
+ /// return array.lazy.filter { !predicate($0) }.isEmpty
711
755
/// }
712
- /// }
713
- /// }
714
- /// ```
756
+ /// // error: closure use of non-escaping parameter 'predicate'...
757
+ ///
758
+ /// `withoutActuallyEscaping(_:do:)` provides a temporarily-escapable copy of
759
+ /// `predicate` that _can_ be used in a call to the lazy view's `filter(_:)`
760
+ /// method. The second version of `allValues(in:match:)` compiles without
761
+ /// error, with the compiler guaranteeing that the `escapablePredicate`
762
+ /// closure doesn't last beyond the call to `withoutActuallyEscaping(_:do:)`.
763
+ ///
764
+ /// func allValues(in array: [Int], match predicate: (Int) -> Bool) -> Bool {
765
+ /// return withoutActuallyEscaping(predicate) { escapablePredicate in
766
+ /// array.lazy.filter { !escapablePredicate($0) }.isEmpty
767
+ /// }
768
+ /// }
769
+ ///
770
+ /// Asynchronous calls are another type of API that typically escape their
771
+ /// closure arguments. The following code declares a
772
+ /// `perform(_:simultaneouslyWith:)` function that uses a dispatch queue to
773
+ /// execute two closures concurrently.
774
+ ///
775
+ /// func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void) {
776
+ /// let queue = DispatchQueue(label: "perform", attributes: .concurrent)
777
+ /// queue.async(execute: f)
778
+ /// queue.async(execute: g)
779
+ /// queue.sync(flags: .barrier) {}
780
+ /// }
781
+ /// // error: passing non-escaping parameter 'f'...
782
+ /// // error: passing non-escaping parameter 'g'...
783
+ ///
784
+ /// The `perform(_:simultaneouslyWith:)` function ends with a call to the
785
+ /// `sync(flags:execute:)` method using the `.barrier` flag, which forces the
786
+ /// function to wait until both closures have completed running before
787
+ /// returning. Even though the barrier guarantees that neither closure will
788
+ /// escape the function, the `async(execute:)` method still requires that the
789
+ /// closures passed be marked as `@escaping`, so the first version of the
790
+ /// function does not compile. To resolve this, you can use
791
+ /// `withoutActuallyEscaping(_:do:)` to get copies of `f` and `g` that can be
792
+ /// passed to `async(execute:)`.
793
+ ///
794
+ /// func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void) {
795
+ /// withoutActuallyEscaping(f) { escapableF in
796
+ /// withoutActuallyEscaping(g) { escapableG in
797
+ /// let queue = DispatchQueue(label: "perform", attributes: .concurrent)
798
+ /// queue.async(execute: escapableF)
799
+ /// queue.async(execute: escapableG)
800
+ /// queue.sync(flags: .barrier) {}
801
+ /// }
802
+ /// }
803
+ /// }
804
+ ///
805
+ /// - Important: The escapable copy of `closure` passed as `body` is only valid
806
+ /// during the call to `withoutActuallyEscaping(_:do:)`. It is undefined
807
+ /// behavior for the escapable closure to be stored, referenced, or executed
808
+ /// after the function returns.
715
809
///
716
810
/// - Parameter closure: A non-escaping closure value that will be made
717
- /// escapable for the duration of the execution of the `do` block.
718
- /// - Parameter do: A code block that will be immediately executed, receiving
719
- /// an escapable copy of `closure` as an argument.
720
- /// - Returns: the forwarded return value from the `do` block.
721
- /// - Remark: It is undefined behavior for the escapable closure to be stored,
722
- /// referenced, or executed after `withoutActuallyEscaping` returns. A
723
- /// future version of Swift will introduce a dynamic check to trap if
724
- /// the escapable closure is still referenced at the point
725
- /// `withoutActuallyEscaping` returns.
811
+ /// escapable for the duration of the execution of the `body` closure. If
812
+ /// `body` has a return value, it is used as the return value for the
813
+ /// `withoutActuallyEscaping(_:do:)` function.
814
+ /// - Parameter body: A closure that will be immediately executed, receiving an
815
+ /// escapable copy of `closure` as an argument.
816
+ /// - Returns: The return value of the `body` closure, if any.
726
817
@_transparent
727
818
@_semantics ( " typechecker.withoutActuallyEscaping(_:do:) " )
728
819
public func withoutActuallyEscaping< ClosureType, ResultType> (
729
820
_ closure: ClosureType ,
730
- do: ( _ escapingClosure: ClosureType ) throws -> ResultType
821
+ do body : ( _ escapingClosure: ClosureType ) throws -> ResultType
731
822
) rethrows -> ResultType {
732
823
// This implementation is never used, since calls to
733
824
// `Swift.withoutActuallyEscaping(_:do:)` are resolved as a special case by
0 commit comments