Skip to content

Remove stale embedded swift documentation #82395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 1 addition & 56 deletions docs/EmbeddedSwift/ABI.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,3 @@
# Embedded Swift -- ABI

**⚠️ Embedded Swift is experimental. This document might be out of date with latest development.**

**‼️ Use the latest downloadable 'Trunk Development' snapshot from swift.org to use Embedded Swift. Public releases of Swift do not yet support Embedded Swift.**

For an introduction and motivation into Embedded Swift, please see "[A Vision for Embedded Swift](https://github.com/swiftlang/swift-evolution/blob/main/visions/embedded-swift.md)", a Swift Evolution document highlighting the main goals and approaches.

## ABI stability

The ABI of code generated by Embedded Swift is not currently stable. For a concrete compiler version, it will be consistent, but do not mix code built with different compiler versions.

Similarly, do not mix Embedded Swift code with full Swift code, as the ABIs are different. Details are described in the following sections.

## Symbol mangling under Embedded Swift

Since Swift 5.0, the stable ABI mangling schema uses the `$s` prefix on all Swift symbols. Because Embedded Swift's ABI differs from the stable ABI, and furthermore because it's not expected to be stable, Embedded Swift uses a `$e` mangling prefix. The logic and structure of the mangling stays the same, the only difference is the prefix.

## Calling convention of Embedded Swift

As of today, Embedded Swift has identical calling convention to full Swift. However, this does not need to continue in the future, and there should not be expectations that the ABI of Embedded Swift is compatible with full Swift.

The compiler respects the ABIs and calling conventions of C and C++ when interoperating with code in those languages. Calling C/C++ functions from Embedded Swift code is supported, and similarly exporting Swift code via `@_extern`, `@_cdecl` or `@_expose` will match the right calling conventions that C/C++ expects.

## Metadata ABI of Embedded Swift

Embedded Swift eliminates almost all metadata compared to full Swift. However, class and existential metadata are still used, because those serve as vtables and witness tables for dynamic dispatch of methods to implement runtime polymorphism with classes and existentials.

### Class Metadata ABI

The layout of Embedded Swift's class metadata is *different* from full Swift:

- The **super pointer** pointing to the class metadata record for the superclass is stored at **offset 0**. If the class is a root class, it is null.
- The **destructor pointer** is stored at **offset 1**. This function is invoked by Swift's deallocator when the class instance is destroyed.
- The **ivar destroyer** is stored at **offset 2**. This function is invoked to destroy instance members when creation of the object is cancelled (e.g. in a failable initializer).
- Lastly, the **vtable** is stored at **offset 3**: For each Swift class in the class's inheritance hierarchy, in order starting
from the root class and working down to the most derived class, the function pointers to the implementation of every method of the class in declaration order in stored.

### Witness Tables ABI

The layout of Embedded Swift's witness tables is *different* from full Swift:

- The first word is always a null pointer (TODO: it can be eliminated)
- The following words are witness table entries which can be one of the following:
- A method witness: a pointer to the witness function.
- An associated conformance witness: a pointer to the witness table of the associated conformance

Note that witness tables in Embedded Swift do not contain associated type entries.

Witness functions are always specialized for concrete types. This also means that parameters and return values are passed directly (if possible).

## Heap object layout in Embedded Swift

Heap objects have the following layout in Embedded Swift:

- The **isa pointer** (pointer to the class metadata) is stored at **offset 0**.
- The **refcount** is stored inline at **offset 1**.
- Normal stored properties follow.
Embedded Swift documentation has moved to: [Swift.org](https://docs.swift.org/embedded/documentation/embedded).
76 changes: 1 addition & 75 deletions docs/EmbeddedSwift/EmbeddedSwiftStatus.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,3 @@
# Embedded Swift -- Status

**⚠️ Embedded Swift is experimental. This document might be out of date with latest development.**

**‼️ Use the latest downloadable 'Trunk Development' snapshot from swift.org to use Embedded Swift. Public releases of Swift do not yet support Embedded Swift.**

For an introduction and motivation into Embedded Swift, please see "[A Vision for Embedded Swift](https://github.com/swiftlang/swift-evolution/blob/main/visions/embedded-swift.md)", a Swift Evolution document highlighting the main goals and approaches.

## Embedded Swift Language Features

| **Language Feature** | **Currently Supported In Embedded Swift** |
|-------------------------------------------------------|------------------------------------------------------------------------------------|
| *Anything not listed below* | Yes |
| Library Evolution (resilience) | No, intentionally unsupported long-term |
| Objective-C interoperability | No, intentionally unsupported long-term |
| Non-WMO builds | No, intentionally unsupported long-term (WMO should be used) |
| Existentials (values of protocol types) | Only class-bound existentials (for protocols derived from AnyObject) are supported |
| Any | No, currently disallowed |
| AnyObject | Yes |
| Metatypes | No, currently only allowed as unused arguments (type hints) |
| Untyped throwing | No, intentionally unsupported long-term (typed throwing should be used instead) |
| Weak references, unowned references | No |
| Non-final generic class methods | No, intentionally unsupported long-term, see <[Embedded Swift -- Non-final generic methods](NonFinalGenericMethods.md)>|
| Parameter packs (variadic generics) | No, not yet supported |

## Embedded Standard Library Breakdown

This status table describes which of the following standard library features can be used in Embedded Swift:

| **Swift Standard Library Feature** | **Currently Supported In Embedded Swift?** |
|------------------------------------------------------------|-----------------------------------------------------|
| Array (dynamic heap-allocated container) | Yes |
| Array slices | Yes |
| assert, precondition, fatalError | Partial, only StaticStrings can be used as a failure message |
| Bool, Integer types, Float types | Yes |
| Codable, Encodable, Decodable | No |
| Collection + related protocols | Yes |
| Collection algorithms (sort, reverse) | Yes |
| CustomStringConvertible, CustomDebugStringConvertible | Yes, except those that require reflection (e.g. Array's .description) |
| Dictionary (dynamic heap-allocated container) | Yes |
| Floating-point conversion to string | No |
| Floating-point parsing | No |
| FixedWidthInteger + related protocols | Yes |
| Hashable, Equatable, Comparable protocols | Yes |
| InputStream, OutputStream | No |
| Integer conversion to string | Yes |
| Integer parsing | Yes |
| KeyPaths | Partial (only compile-time constant key paths to stored properties supported, only usable in MemoryLayout and UnsafePointer APIs) |
| Lazy collections | Yes |
| ManagedBuffer | Yes |
| Mirror (runtime reflection) | No, intentionally unsupported long-term |
| Objective-C bridging | No, intentionally unsupported long-term |
| Optional | Yes |
| print / debugPrint | Partial (only String, string interpolation, StaticStrings, integers, pointers and booleans, and custom types that are CustomStringConvertible) |
| Range, ClosedRange, Stride | Yes |
| Result | Yes |
| Set (dynamic heap-allocated container) | Yes |
| SIMD types | Yes |
| StaticString | Yes |
| String (dynamic) | Yes |
| String interpolations | Partial (only strings, integers, booleans, and custom types that are CustomStringConvertible can be interpolated) |
| Unicode | Yes |
| Unsafe\[Mutable\]\[Raw\]\[Buffer\]Pointer | Yes |
| VarArgs | No |

## Non-stdlib Features

This status table describes which of the following Swift features can be used in Embedded Swift:

| **Swift Feature** | **Currently Supported In Embedded Swift?** |
|------------------------------------------------------------|-----------------------------------------------------|
| Synchronization module | Partial (only Atomic types, no Mutex) |
| Swift Concurrency | Partial, experimental (basics of actors and tasks work in single-threaded concurrency mode) |
| C interop | Yes |
| C++ interop | Yes |
| ObjC interop | No, intentionally unsupported long-term |
| Library Evolution | No, intentionally unsupported long-term |
Embedded Swift documentation has moved to: [Swift.org](https://docs.swift.org/embedded/documentation/embedded).
107 changes: 1 addition & 106 deletions docs/EmbeddedSwift/Existentials.md
Original file line number Diff line number Diff line change
@@ -1,108 +1,3 @@
# Embedded Swift -- Existentials

**⚠️ Embedded Swift is experimental. This document might be out of date with latest development.**

**‼️ Use the latest downloadable 'Trunk Development' snapshot from swift.org to use Embedded Swift. Public releases of Swift do not yet support Embedded Swift.**

For an introduction and motivation into Embedded Swift, please see "[A Vision for Embedded Swift](https://github.com/swiftlang/swift-evolution/blob/main/visions/embedded-swift.md)", a Swift Evolution document highlighting the main goals and approaches.

## Background

Existentials (also known as "any" types) in Swift are a way to express a type-erased value, where the actual type is not known statically, and at runtime it can be any type that conforms to the specified protocol. Because the possible types can vary in size, the representation of such a value is an "existential container" and the actual represented value is stored either inline (when it fits) or indirectly as a pointer to a heap allocation. There are also multiple concrete representations of the existential container that are optimized for different constraints (e.g. for class-bound existentials, the value does not make sense to ever store inline, so the size of the container is matched to hold exactly one pointer).

Existentials are restricted in Embedded Swift in multiple ways, for multiple reasons:

- Value existentials are not allowed. This prevents the optimization barriers and heap allocation indirections that come with those existentials in regular Swift.
- Class-bound protocols can be used as an existential. This still circumvents the often undesired behavior of existentials where they allocate (and deallocate) storage on the heap for the inner value if it cannot fit in the inline buffer, because class references are always refcounted and references are shared.
- Unbounded generic methods cannot be called through an existential.

## Class-bound existentials

Embedded Swift allows and supports class-bound existentials:

```swift
procotol ClassBoundProtocol: AnyObject { // ✅, this means any type that wants to conform to ClassBoundProtocol must be a class type
func foo()
}

class Base: ClassBoundProtocol { ... }
class Derived: Base { ... } // also conforms to ClassBoundProtocol
class Other: ClassBoundProtocol { ... }

let existential: any ClassBoundProtocol = ... // ✅
existential.foo() // ✅
```

Note that protocols that are not class-bound cannot form existentials (in Embedded Swift):

```swift
let existential: any Equatable = ... // ❌

class MyClass: Equatable { ... }
let existential: any Equatable = MyClass // ❌, not enough that the actual type is a class, the protocol itself must be class-bound
```

Class-bound existentials in Embedded Swift allow the "is" and "as!" / "as?" operators:

```swift
let existential: any ClassBoundProtocol = ...
if existential is Base { ... } // ✅
guard let concrete = existential as? Derived else { ... } // ✅
let concrete = existential as! Derived // ✅, and will trap at runtime if a different type is inside the existential
```

## Restrictions on class-bound existentials

Class-bound existentials in Embedded Swift do come with some restrictions compared to class-bound existentials in regular Swift:

- You cannot use an existential to call a unbounded generic method from the protocol. This is described in depth in [Embedded Swift -- Non-final generic methods](NonFinalGenericMethods.md). For example:
```swift
protocol ClassBoundProtocol: AnyObject {
func foo<T>(t: T)
}

let ex: any ClassBoundProtocol = ... // ✅
ex.foo(t: 42) // ❌
```

- You cannot use an existential composition of a class-bound protocol with a non-class-bound protocol. For example:
```swift
let ex: any ClassBoundProtocol & OtherClassBound = ... // ✅
let ex: any ClassBoundProtocol & Equatable = ... // ❌
```

## Alternatives to existentials

When existentials are not possible (e.g. because you need struct types in an existential), or not desirable (e.g. because the indirection on a class-bound existential causes an observation performance degradation), consider one of the following alternatives (which all have different tradeoffs and code structure implications):

**(1) Avoid using an existential, use generics instead**

```swift
protocol MyProtocol {
func write<T>(t: T)
}

func usingProtocolAsGeneric(p: some MyProtocol) {
p.write(t: 42) // ✅
}
```

**(2) If you only need a different type based on compile-time configuration (e.g. mocking for unit testing), use #if and typealiases:**
```swift
#if UNIT_TESTING
typealias HWAccess = MMIOBasedHWAccess
#else
typealias HWAccess = MockHWAccess
#endif

let v = HWAccess()
```

**(3) If you only have a handful of tightly-coupled types that need to participate in an existential, use an enum instead:**
```swift
enum E {
case type1(Type1)
case type2(Type2)
case type3(Type3)
}
```
Embedded Swift documentation has moved to: [Swift.org](https://docs.swift.org/embedded/documentation/embedded).
Loading