diff --git a/docs/Lexicon.md b/docs/Lexicon.md index bd4303711131d..987b32cf2a4cd 100644 --- a/docs/Lexicon.md +++ b/docs/Lexicon.md @@ -67,6 +67,17 @@ and the combination of module path + access path is an "import path".) See `ImportPath` and the types nested inside it for more on this. +## access pattern + +Defines how some particular storage (a property or a subscript) is accessed. +For example, when accessing a property `let y = a.x`, the compiler could potentially +use `get` accessor or the `_read` accessor. Similarly, for a modification like +`a.x += 1`, the compiler could use `get` + `set` or it could use `_modify`. + +The access pattern can differ for call-sites which can/cannot see the underlying +implementation. Clients which cannot see the underlying implementation are said +to use the conservative access pattern. + ## archetype A placeholder for a generic parameter or an associated type within a @@ -476,6 +487,38 @@ See [mandatory passes](#mandatory-passes--mandatory-optimizations). An implicit representation change that occurs when a value is used with a different [abstraction pattern](#abstraction-pattern) from its current representation. +## realization + +The process of initializing an ObjC class for use by the ObjC runtime. +This consists of allocating runtime tracking data, fixing up method lists +and attaching categories. + +This is distinct from the initialization performed by `+initialize`, which +happens only when the first message (other than `+load`) is sent to the class. + +The order of operations is: realization, followed by `+load` (if present), +followed by `+initialize`. There are few cases where these can happen +at different times. + +- Common case (no `+load` or special attributes): Realization is lazy and + happens when the first message is sent to a class. After that, `+initialize` + is run. +- If the class has a `+load` method: `+load`, as the name suggests, runs at + load time; it is the ObjC equivalent of a static initializer in C++. For + such a class, realization eagerly happens at load time before `+load` runs. + (Fun aside: C++ static initializers run after `+load`.) `+initialize` still + runs lazily on the first message. +- If the class is marked [`@_objc_non_lazy_realization`](/docs/ReferenceGuides/UnderscoredAttributes.md#_objc_non_lazy_realization): + Realization happens at load time. `+initialize` still runs lazily on the first + message. + +It's possible to create a class that is realized but not initialized by +using a runtime function like `objc_getClass` before the class has been used. + +See also: Mike Ash's blog post on +[Objective-C Class Loading and Initialization](https://www.mikeash.com/pyblog/friday-qa-2009-05-22-objective-c-class-loading-and-initialization.html), +which covers `+load` and `+initialize` in more detail. + ## refutable pattern A pattern that may not always match. These include patterns such as: diff --git a/docs/README.md b/docs/README.md index 98472f2db27ba..c9d89fc9aa2bb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -177,6 +177,8 @@ documentation, please create a thread on the Swift forums under the - [Lexicon.md](/docs/Lexicon.md): Canonical reference for terminology used throughout the project. +- [UnderscoredAttributes.md](/docs/ReferenceGuides/UnderscoredAttributes.md): + Documents semantics for underscored (unstable) attributes. ### ABI diff --git a/docs/ReferenceGuides/UnderscoredAttributes.md b/docs/ReferenceGuides/UnderscoredAttributes.md new file mode 100644 index 0000000000000..229f4fedbfcfc --- /dev/null +++ b/docs/ReferenceGuides/UnderscoredAttributes.md @@ -0,0 +1,612 @@ +# Underscored Attributes Reference + +**WARNING:** This information is provided primarily for compiler and standard +library developers. Usage of these attributes outside of the Swift monorepo +is STRONGLY DISCOURAGED. + +The Swift reference has a chapter discussing [stable attributes][Attributes]. +This document is intended to serve as a counterpart describing underscored +attributes, whose semantics are subject to change and most likely need to +go through the Swift evolution process before being stabilized. + +[Attributes]: https://docs.swift.org/swift-book/ReferenceManual/Attributes.html + +The attributes are organized in alphabetical order. + +## `@_alignment(numericValue)` + +Allows controlling the alignment of a type. + +The alignment value specified must be a power of two, and cannot be less +than the "natural" alignment of the type that would otherwise be used by +the Swift ABI. This attribute is intended for the SIMD types in the standard +library which use it to increase the alignment of their internal storage to at +least 16 bytes. + +## `@_alwaysEmitIntoClient` + +Forces the body of a function to be emitted into client code. + +Note that this is distinct from `@inline(__always)`; it doesn't force inlining +at call-sites, it only means that the implementation is compiled into the +module which uses the code. + +This means that `@_alwaysEmitIntoClient` definitions are _not_ part of the +defining module's ABI, so changing the implementation at a later stage +does not break ABI. + +Most notably, default argument expressions are implicitly +`@_alwaysEmitIntoClient`, which means that adding a default argument to a +function which did not have one previously does not break ABI. + +## `@_borrowed` + +Indicates that the [conservative access pattern](/docs/Lexicon.md#access-pattern) +for some storage (a subscript or a property) should use the `_read` accessor +instead of `get`. + +For more details, see the forum post on +[Value ownership when reading from a storage declaration](https://forums.swift.org/t/value-ownership-when-reading-from-a-storage-declaration/15076). + +## `@_cdecl("cName")` + +Similar to `@_silgen_name` but uses the C calling convention. + +This attribute doesn't have very well-defined semantics. Type bridging is not +done, so the parameter and return types should correspond directly to types +accessible in C. In most cases, it is preferable to define a static method +on an `@objc` class instead of using `@_cdecl`. + +For potential ideas on stabilization, see +[Formalizing `@cdecl`](https://forums.swift.org/t/formalizing-cdecl/40677). + +## `@_disfavoredOverload` + +Marks an overload that the type checker should try to avoid using. When the +expression type checker is considering overloads, it will prefer a solution +with fewer `@_disfavoredOverload` declarations over one with more of them. + +Use `@_disfavoredOverload` to work around known bugs in the overload +resolution rules that cannot be immediately fixed without a source break. +Don't use it to adjust overload resolution rules that are otherwise sensible +but happen to produce undesirable results for your particular API; it will +likely be removed or made into a no-op eventually, and then you will be +stuck with an overload set that cannot be made to function in the way +you intend. + +`@_disfavoredOverload` was first introduced to work around a bug in overload +resolution with `ExpressibleByXYZLiteral` types. The type checker strongly +prefers to give literals their default type (e.g. `Int` for +`ExpressibleByIntegerLiteral`, `String` for `ExpressibleByStringLiteral`, +etc.). If an API should prefer some other type, but accept the default too, + marking the declaration taking the default type with `@_disfavoredOverload` + gives the desired behavior: + +```swift +extension LocalizedStringKey: ExpressibleByStringLiteral { ... } + +extension Text { + // We want `Text("foo")` to use this initializer: + init(_ key: LocalizedStringKey) { ... } + + // But without @_disfavoredOverload, it would use this one instead, + // because that lets it give the literal its default type: + @_disfavoredOverload init(_ str: S) { ... } +} +``` + +## `@_dynamicReplacement(for:)` + +Marks a function as the dynamic replacement for another `dynamic` function. +This is similar to method swizzling in other languages such as Objective-C, +except that the replacement happens at program start (or loading a shared +library), instead of at an arbitrary point in time. + +For more details, see the forum post on +[Dynamic method replacement](https://forums.swift.org/t/dynamic-method-replacement/16619). + +## `@_distributedActorIndependent` + +Marks a specific property of a distributed actor to be available even if the +actor is remote. + +This only applies to two distributed actor properties `address` and `transport`. +It cannot be safely declared on any properties defined by ordinary Swift code. + +## `@_effects(effectname)` + +Tells the compiler that the implementation of the defined function is limited +to certain side effects. The attribute argument specifies the kind of side +effect limitations that apply to the function including any other functions +it calls. This is used to provide information to the optimizer that it can't +already infer from static analysis. + +Changing the implementation in a way that violates the optimizer's assumptions +about the effects results in undefined behavior. + +For more details, see [OptimizerEffects.rst](/docs/Proposals/OptimizerEffects.rst). + +## `@_exported` + +Re-exports all declarations from an imported module. + +This attribute is most commonly used by overlays. + +```swift +// module M +func f() {} + +// module N +@_exported import M + +// module P +import N +func g() { + N.f() // OK +} +``` + +## `@_fixed_layout` + +Same as `@frozen` but also works for classes. + +With `@_fixed_layout` classes, vtable layout still happens dynamically, so +non-public virtual methods can be removed, new virtual methods can be added, +and existing virtual methods can be reordered. + +## `@_hasInitialValue` + +Marks that a property has an initializing expression. + +This information is lost in the swiftinterface, +but it is required as it results in a symbol for the initializer +(if a class/struct `init` is inlined, it will call initializers +for properties that it doesn't initialize itself). +This information is necessary for correct TBD file generation. + +## `@_hasMissingDesignatedInitializers` + +Indicates that there may be designated initializers that are +not printed in the swiftinterface file for a particular class. + +This attribute is needed for the initializer model to maintain correctness when +[library evolution](/docs/LibraryEvolution.rst) is enabled. This is because a +class may have non-public designated initializers, and Swift allows the +inheritance of convenience initializers if and only if the subclass overrides +(or has synthesized overrides) of every designated initializer in its +superclass. Consider the following code: + +```swift +// Lib.swift +open class A { + init(invisible: ()) {} + + public init(visible: ()) {} + public convenience init(hi: ()) { self.init(invisible: ()) } +} + +// Client.swift +class B : A { + var x: String + + public override init(visible: ()) { + self.x = "Garbage" + super.init(visible: ()) + } +} +``` + +In this case, if `B` were allowed to inherit the convenience initializer +`A.init(invisible:)` then an instance created via `B(hi: ())` would fail +to initialize `B.x` resulting in a memory safety hole. What's worse is +there is no way to close this safety hole because the user cannot override +the invisible designated initializer because they lack sufficient visibility. + +## `@_hasStorage` + +Marks a property as being a stored property in a swiftinterface. + +For `@frozen` types, the compiler needs to be able to tell whether a particular +property is stored or computed to correctly perform type layout. + +``` +@frozen struct S { + @_hasStorage var x: Int { get set } // stored + var y: Int { get set } // computed +} +``` + +## `@_implementationOnly` + +Used to mark an imported module as an implementation detail. +This prevents types from that module being exposed in API +(types of public functions, constraints in public extension etc.) +and ABI (usage in `@inlinable` code). + +## `@_implements(ProtocolName, Requirement)` + +An attribute that indicates that a function with one name satisfies +a protocol requirement with a different name. This is especially useful +when two protocols declare a requirement with the same name, but the +conforming type wishes to offer two separate implementations. + +```swift +protocol P { func foo() } + +protocol Q { func foo() } + +struct S : P, Q { + @_implements(P, foo()) + func foo_p() {} + @_implements(Q, foo()) + func foo_q() {} +} +``` + +## `@_implicitSelfCapture` + +Allows access to `self` inside a closure without explicitly capturing it, +even when `Self` is a reference type. + +```swift +class C { + func f() {} + func g(_: @escaping () -> Void { + g({ f() }) // error: call to method 'f' in closure requires explicit use of 'self' + } + func h(@_implicitSelfCapture _: @escaping () -> Void) { + h({ f() }) // ok + } +} +``` + +## `@_inheritActorContext` + +(Note that it is "inherit", not "inherits", unlike below.) + +Marks that a `@Sendable async` closure argument should inherited the actor +context (i.e. what actor it should be run on) based on the declaration site +of the closure. This is different from the typical behavior, where the closure +may be runnable anywhere unless its type specifically declares that it will +run on a specific actor. + +This new attribute can be used on parameters of `@Sendable async` type +to indicate that the closures arguments passed to such parameters +should inherit the actor context where they are formed, which is not +the normal behavior for `@Sendable` closures. + +## `@_inheritsConvenienceInitializers` + +An attribute that signals that a class declaration inherits its convenience +initializers from its superclass. This implies that all designated initializers +-- even those that may not be visible in a swiftinterface file -- are +overridden. This attribute is often printed alongside +`@_hasMissingDesignatedInitializers` in this case. + +## `@_marker` + +Indicates that a protocol is a marker protocol. Marker protocols represent some +meaningful property at compile-time but have no runtime representation. + +For more details, see [SE-0302](https://github.com/apple/swift-evolution/blob/main/proposals/0302-concurrent-value-and-concurrent-closures.md#marker-protocols), which introduces marker protocols. + +At the moment, the language only has one marker protocol: `Sendable`. + +Fun fact: Rust has a very similar concept called +[marker traits](https://doc.rust-lang.org/std/marker/index.html), +including one called `Send`, +which inspired the design of `Sendable`. + +## `@_nonEphemeral` + +Marks a function parameter that cannot accept a temporary pointer produced from +an inout-to-pointer, array-to-pointer, or string-to-pointer conversion. Such a +parameter may only accept a pointer that is guaranteed to outlive the duration +of the function call. + +Attempting to pass a temporary pointer to an `@_nonEphemeral` parameter will +produce a warning. This attribute is primarily used within the standard library +on the various `UnsafePointer` initializers to warn users about +the undefined behavior caused by using a temporary pointer conversion as an +argument: + +```swift +func baz() { + var x = 0 + + // warning: Initialization of 'UnsafePointer' results in a dangling pointer + let ptr = UnsafePointer(&x) + + // warning: Initialization of 'UnsafePointer' results in a dangling pointer + let ptr2 = UnsafePointer([1, 2, 3]) +} +``` + +The temporary pointer conversion produces a pointer that is only +guaranteed to be valid for the duration of the call to the initializer, +and becomes invalid once the call ends. +So the newly created `UnsafePointer` will be dangling. + +One exception to this is that inout-to-pointer conversions +on static stored properties and global stored properties +produce non-ephemeral pointers, as long as they have no observers: + +```swift +var global = 0 + +struct S { + static var staticVar = 0 +} + +func baz() { + let ptr = UnsafePointer(&global) // okay + let ptr2 = UnsafePointer(&S.staticVar) // okay +} +``` + +Additionally, if they are of a tuple or struct type, their stored members +without observers may also be passed inout as non-ephemeral pointers. + +For more details, see the educational note on +[temporary pointer usage](/userdocs/diagnostics/temporary-pointers.md). + +## `@_nonoverride` + +Marks a declaration that is not an override of another. +When the `-warn-implicit-overrides` flag is used, a warning is issued when a +protocol restates a requirement from another protocol it refines without +annotating the declaration with either `override` or `@_nonoverride`. + +An `override` annotation causes the overriding declaration to be treated +identically to the overridden declaration; a conforming type can only +provide one implementation ("witness"). Restating a protocol requirement +and then marking it as an `override` is generally only needed to help +associated type inference, and many `override` annotations correlate +closely with ABI FIXMEs. + +Meanwhile, `@_nonoverride` is the "opposite" of `override`, allowing two +protocol requirements to be treated independently; a conforming type can +provide a distinct witness for each requirement (for example, by using +`@_implements`). Use `@_nonoverride` when semantics differ between the +two requirements. For example, `BidirectionalCollection.index(_:offsetBy:)` +allows negative offsets, while `Collection.index(_:offsetBy:)` does not, +and therefore the former is marked `@_nonoverride`. + +The `@_nonoverride` annotation can also be specified on class members in +addition to protocol members. Since it is the "opposite" of `override`, it can +be used to suppress "near-miss" diagnostics for declarations that are similar +to but not meant to override another declaration, and it can be used to +intentionally break the override chain, creating an overload instead of an +override. + +This attribute and the corresponding `-warn-implicit-overrides` flag are +used when compiling the standard library and overlays. + +## `@_objc_non_lazy_realization` + +Marks a class as being non-lazily (i.e. eagerly) [realized](/docs/Lexicon.md#realization). + +This is used for declarations which may be statically referenced and wouldn't +go through the normal lazy realization paths. For example, the empty array +class must be non-lazily realized, because empty arrays are statically +allocated. Otherwise, passing the empty array object to other code without +triggering realization could allow for the unrealized empty array class to be +passed to ObjC runtime APIs which only operate on realized classes, resulting +in a crash. + +## `@_optimize([none|size|speed])` + +Controls the compiler's optimization mode. This attribute is analogous to the +command-line flags `-Onone`, `-Osize` and `-Ospeed` respectively, but limited +to a single function body. + +`@_optimize(none)` is handy for diagnosing and reducing compiler bugs as well +as improving debugging in Release builds. + +## `@_originallyDefinedIn(module: "ModuleName", availabilitySpec...)` + +Marks a declaration as being originally defined in a different module, +changing the name mangling. This can be used to move declarations +from a module to one of the modules it imports without breaking clients. + +Consider the following example where a framework ToasterKit needs +to move some APIs to a lower-level framework ToasterKitCore. +Here are the necessary changes: + +1. Add a linker flag `-reexport_framework ToasterKitCore` for ToasterKit. + This ensures all symbols defined in ToasterKitCore will be accessible during + runtime via ToasterKit, so existing apps continue to run. +2. In ToasterKit, use `@_exported import ToasterKitCore`. + This ensures existing source code that only imports ToasterKit continues to + type-check. +3. Move the necessary declarations from ToasterKit to ToasterKitCore. + The moved declaration should have two attributes: + - `@available` indicating when the declaration was introduced in ToasterKit. + - `@_originallyDefinedIn` indicating the original module and when the + declaration was moved to ToasterKitCore. + ```swift + @available(toasterOS 42, *) + @_originallyDefinedIn(module: "ToasterKit", toasterOS 57) + enum Toast { + case underdone + case perfect + case burnt + } + ``` +4. Add Swift compiler flags `-Xfrontend -emit-ldadd-cfile-path -Xfrontend /tmp/t.c` + to ToasterKitCore's build settings. Add the emitted `/tmp/t.c` file to + ToasterKit's compilation. + This ensures when an app is built for deployment targets prior to the symbols' move, + the app will look for these symbols in ToasterKit instead of ToasterKitCore. + +More generally, mutliple availabilities can be specified, like so: + +```swift +@available(toasterOS 42, bowlOS 54, mugOS 54, *) +@_originallyDefinedIn(module: "ToasterKit", toasterOS 57, bowlOS 69, mugOS 69) +enum Toast { ... } +``` + +## `@_private(sourceFile: "FileName.swift")` + +Fully bypasses access control, allowing access to private declarations +in the imported module. The imported module needs to be compiled with +`-Xfrontend -enable-private-imports` for this to work. + +## `@_semantics("uniquely.recognized.id")` + +Allows the optimizer to make use of some key invariants in performance critical +data types, especially `Array`. Since the implementation of these data types +is written in Swift using unsafe APIs, without these attributes the optimizer +would need to make conservative assumptions. + +Changing the implementation in a way that violates the optimizer's assumptions +about the semantics results in undefined behavior. + +## `@_show_in_interface` + +Shows underscored protocols from the standard library in the generated interface. + +By default, SourceKit hides underscored protocols from the generated +swiftinterface (for all modules, not just the standard library), but this +attribute can be used to override that behavior for the standard library. + +## `@_silgen_name("cName")` + +Changes the symbol name for a function, similar to an ASM label in C, +except that the platform symbol mangling (leading underscore on Darwin) +is maintained. + +Since this has label-like behavior, it may not correspond to any declaration; +if so, it is assumed that the function is implemented in C. + +A function defined by `@_silgen_name` is assumed to use the Swift ABI. + +For more details, see the +[Standard Library Programmer's Manual](https://github.com/apple/swift/blob/main/docs/StandardLibraryProgrammersManual.md#_silgen_name). + +## `@_specialize(...)` + +Forces generation of a specialized implementation for a generic declaration. + +See [Generics.rst](/docs/Generics.rst) for more details. + +## `@_specializeExtension` + +Allows extending `@usableFromInline` internal types from foreign modules. +Consider the following example involving two modules: + +```swift +// Module A +@usableFromInline +internal struct S { /* ... */ } + +// Module B +import A + +@_specializeExtension +extension S { // OK + // add methods here +} + +extension S /* or A.S */ { // error: cannot find 'S' in scope +} +``` + +This ability can be used to add specializations of existing methods +in downstream libraries when used in conjunction with `@_specialize`. + +```swift +// Module A +@usableFromInline +internal struct S { + @inlinable + internal func doIt() { /* body */ } +} + +// Module B +import A + +@_specializeExtension +extension S { // ok + @_specialize(exported: true, target: doIt(), where T == Int) + public func specializedDoIt() {} +} + +// Module C +import A +import B + +func f(_ s: S) { + s.doIt() // will call specialized version of doIt() where T == Int from B +} +``` + +## `@_spi(spiName)` + +Marks a declaration as SPI (System Programming Interface), instead of API. +Modules exposing SPI and using library evolution generate an additional +`.private.swiftinterface` file (with `-emit-private-module-interface-path`) +in addition to the usual `.swiftinterface` file. This private interface exposes +both API and SPI. + +Clients can access SPI by marking the import as `@_spi(spiName) import Module`. +This design makes it easy to find out which clients are using certain SPIs by +doing a textual search. + +## `@_staticInitializeObjCMetadata` + +Indicates that a static initializer should be emitted to register the +Objective-C metadata when the image is loaded, rather than on first use of the +Objective-C metadata. + +This attribute is inferred for `NSCoding` classes that won't +have static Objective-C metadata or have an `@NSKeyedArchiveLegacy` attribute. + +## `@_transparent` + +Marks a function to be "macro-like", i.e., it is guaranteed to be inlined +in debug builds. + +See [TransparentAttr.md](/docs/TransparentAttr.md) for more details. + +## `@_typeEraser(Proto)` + +Marks a concrete nominal type as one that implements type erasure for a +protocol `Proto`. + +A type eraser has the following restrictions: + +1. It must be a concrete nominal type. +2. It must not have more restrictive access than `Proto`. +3. It must conform to `Proto`. +4. It must have an initializer of the form `init(erasing: T)`. + - Other generic requirements are permitted as long as the `init` can always + be called with a value of any type conforming to `Proto`. + - The `init` cannot have more restrictive access than `Proto`. + +This feature was designed to be used for compiler-driven type erasure for +dynamic replacement of functions with an opaque return type. + +## `@_weakLinked` + +Allows a declaration to be weakly-referenced, i.e., any references emitted by +client modules to the declaration's symbol will have weak linkage. This means +that client code will compile without the guarantee that the symbol will be +available at runtime. This requires a dynamic safety check (such as using +`dlsym (3)`); otherwise, accessing the symbol when it is unavailable leads +to a runtime crash. + +This is an unsafe alternative to using `@available`, which is statically checked. +If the availability of a library symbol is newer than the deployment target of +the client, the symbol will be weakly linked, but checking for `@available` and +`#(un)available` ensures that a symbol is not accessed when it is unavailable. + +## `@_unsafeMainActor`, `@_unsafeSendable` + +Marks a parameter's (function) type as `@MainActor` (`@Sendable`) in Swift 6 and +within Swift 5 code that has adopted concurrency, but non-`@MainActor` +(non-`@Sendable`) everywhere else. + +See the forum post on [Concurrency in Swift 5 and 6](https://forums.swift.org/t/concurrency-in-swift-5-and-6/49337) +for more details.