├── .gitignore ├── Package.swift ├── README.md ├── Sources └── SwiftTypeSystem │ ├── FunctionTypes.swift │ ├── GenericArgument.swift │ ├── GenericParameter.swift │ ├── GenericRequirement.swift │ ├── GenericSignature.swift │ ├── ResolvedName.swift │ ├── SubstitutionMap.swift │ ├── TupleTypes.swift │ ├── TypeSystem.swift │ └── Types.swift └── Tests └── SwiftTypeSystemTests └── SwiftTypeSystemTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/config/registries.json 8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 9 | .netrc 10 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.7 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SwiftTypeSystem", 8 | products: [ 9 | // Products define the executables and libraries a package produces, and make them visible to other packages. 10 | .library( 11 | name: "SwiftTypeSystem", 12 | targets: ["SwiftTypeSystem"]), 13 | ], 14 | dependencies: [ 15 | // Dependencies declare other packages that this package depends on. 16 | // .package(url: /* package url */, from: "1.0.0"), 17 | ], 18 | targets: [ 19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 20 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 21 | .target( 22 | name: "SwiftTypeSystem", 23 | dependencies: []), 24 | .testTarget( 25 | name: "SwiftTypeSystemTests", 26 | dependencies: ["SwiftTypeSystem"]), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftTypeSystem 2 | 3 | An experimental description of the Swift type system as value types, 4 | with the goal of having a single representation that can be used for 5 | both tools and reflection. 6 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/FunctionTypes.swift: -------------------------------------------------------------------------------- 1 | 2 | extension Type { 3 | /// The calling convention used for a function. 4 | public enum FunctionConvention { 5 | /// The normal Swift calling convention. 6 | /// 7 | /// This is the default calling convention for Swift functions, which is 8 | /// able to handle all Swift types and capture state. 9 | case swift 10 | 11 | /// The C calling convention, which can only use types expressible in 12 | /// (Objective-)C and cannot capture any state. 13 | case c 14 | 15 | /// The block calling convention, supporting the C "blocks" extension. 16 | /// 17 | /// These functions can only use types expressible in (Objective-)C, and 18 | /// can capture state. 19 | case block 20 | 21 | /// The normal Swift calling convention but without a context pointer. 22 | /// 23 | /// Thin functions can handle all Swift types, but are represented as a 24 | /// single function pointer and cannot capture state. 25 | case thin 26 | } 27 | 28 | /// Attributes provided for a function. 29 | public struct FunctionAttributes { 30 | /// Whether this function is asynchronous. 31 | public var `async`: Bool 32 | 33 | /// Whether this function can throw. 34 | public var `throws`: Bool 35 | 36 | /// Whether this function is escaping. 37 | public var `escaping`: Bool 38 | 39 | /// Whether this function is `@Sendable`. 40 | public var `sendable`: Bool 41 | 42 | /// The calling convention for the function. 43 | public var convention: FunctionConvention = .swift 44 | 45 | /// The global actor, such as `@MainActor`, on which this function runs. 46 | public var globalActor: Type? 47 | } 48 | 49 | /// The convention used to pass a parameter. 50 | public enum ParameterConvention { 51 | /// An `inout` parameter, which is passed indirectly and can be modified 52 | /// by the callee. 53 | case `inout` 54 | 55 | /// A borrowing parameter, which the callee cannot mutate. 56 | case borrowing 57 | 58 | /// A consuming parameter, which the callee can locally mutate and is 59 | /// responsible for destroying. 60 | case consuming 61 | } 62 | 63 | /// A parameter within a function type. 64 | public struct FunctionTypeParameter { 65 | /// The argument label used when calling the function. 66 | /// 67 | /// Note: this is in the language grammar, but must either be omitted or 68 | /// be `_`. We might not want to model this at all. 69 | public var argumentName: Identifier? 70 | 71 | /// The parameter name. 72 | /// 73 | /// Note: this is in the language grammar, but has no effect on anything. 74 | /// We might not want to model this at all. 75 | public var parameterName: Identifier? 76 | 77 | /// The parameter-passing convention, if specified. 78 | public var convention: ParameterConvention? 79 | 80 | /// Whether the parameter is variadic, i.e., `indices: Int...`. 81 | public var variadic: Bool 82 | 83 | // TODO: There are more bits here 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/GenericArgument.swift: -------------------------------------------------------------------------------- 1 | /// A generic argument. 2 | public enum GenericArgument { 3 | case type(Type) 4 | } 5 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/GenericParameter.swift: -------------------------------------------------------------------------------- 1 | public enum GenericParameter { 2 | public typealias TypeRef = Type 3 | 4 | /// A generic type parameter, e.g., . 5 | case type( 6 | name: Identifier?, 7 | depth: Int, 8 | index: Int, 9 | baggage: System.ResolvedNameBaggage? 10 | ) 11 | 12 | /// A parameter pack. 13 | indirect case parameterPack(GenericParameter) 14 | } 15 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/GenericRequirement.swift: -------------------------------------------------------------------------------- 1 | 2 | /// A constraint on the layout of a type, e.g., it is known to be a class, 3 | /// or be trivial with a fixed size. 4 | public enum LayoutConstraint { 5 | /// Provides a bound on the alignment 6 | public enum SizeBound { 7 | /// The type's exact size and alignment are unknown, but will be no more 8 | /// than the specified values. 9 | case atMost(size: Int, alignment: Int) 10 | 11 | /// The type's size and alignment are known to have precise values. 12 | case exactly(size: Int, alignment: Int) 13 | } 14 | 15 | /// The type is a class. If `native` is `true`, the type is known to be 16 | /// a native Swift class (i.e., not an Objective-C class). 17 | case `class`(native: Bool) 18 | 19 | /// The type is a reference-counted point. If `native` is `true`, the type is 20 | /// known to use Swift's reference counting scheme (i.e., not Objective-C 21 | /// or foreign reference-counting schemes). 22 | case referenceCounted(native: Bool) 23 | 24 | /// The type is known to be trivial, meaning it can be memcpy'd and does not 25 | /// need to be destroyed. The optional bound provides more information about 26 | /// the size and alignment of the type, when available. 27 | case trivial(bound: SizeBound?) 28 | } 29 | 30 | /// A generic requirement that is part of the generic signature of a type, 31 | /// e.g., `C: Collection` or `C.Element == C2.Element`. 32 | public enum GenericRequirement { 33 | public typealias TypeRef = Type 34 | 35 | /// A type bound such as `C: Collection` or `T: SomeSuperclass`. 36 | case typeBound(TypeRef, TypeRef) 37 | 38 | /// A same-type constraint such as `C.Element == C2.Element`. 39 | case sameType(TypeRef, TypeRef) 40 | 41 | /// A same-shape constraint that ensures that two parameter packs have the 42 | /// same shape. 43 | /// 44 | /// Note: this does not have a spelling in the surface language. 45 | case sameShape(TypeRef, TypeRef) 46 | 47 | /// A layout constraint that states that a given type 48 | case layout(TypeRef, LayoutConstraint) 49 | 50 | /// A pack expansion of a generic requirement, e.g., 51 | /// `T.Element = U.Element...`. 52 | /// 53 | /// Note: this might not be part of the variadic generics proposal. 54 | indirect case packExpansion(GenericRequirement) 55 | } 56 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/GenericSignature.swift: -------------------------------------------------------------------------------- 1 | /// A generic signature, which consists of both the generic parameters and 2 | /// generic requirements on those parameters. 3 | public struct GenericSignature { 4 | public var genericParameters: [GenericParameter] 5 | public var requirements: [GenericRequirement] 6 | } 7 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/ResolvedName.swift: -------------------------------------------------------------------------------- 1 | extension Type { 2 | /// Describes how a named type has been resolved. 3 | public struct ResolvedName { 4 | public enum Kind { 5 | /// A struct type. 6 | case `struct` 7 | 8 | /// An enum type. 9 | case `enum` 10 | 11 | /// An actor type. 12 | case `actor` 13 | 14 | /// A class type. 15 | case `class` 16 | 17 | /// A protocol type. 18 | case `protocol` 19 | 20 | /// An associated type. 21 | case associatedType 22 | 23 | /// A named generic parameter. 24 | case genericParameter 25 | 26 | /// A module. 27 | case module 28 | 29 | /// A typealias. 30 | case `typealias` 31 | 32 | /// The 'Self' type. 33 | case selfType 34 | } 35 | 36 | /// The kind of entity to which this name resolved. 37 | public let kind: Kind 38 | 39 | /// Additional baggage associated with the resolved name, which can 40 | /// only be meaningfully interpreted by the specific type system. 41 | public var baggage: System.ResolvedNameBaggage? 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/SubstitutionMap.swift: -------------------------------------------------------------------------------- 1 | /// A substitution map describes a set of substitutions of generic arguments 2 | /// for generic parameters that can be applied to types. 3 | public struct SubstitutionMap { 4 | public let genericSignature: GenericSignature 5 | public let genericArguments: [GenericArgument] 6 | } 7 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/TupleTypes.swift: -------------------------------------------------------------------------------- 1 | public struct TupleTypeElement { 2 | var name: Identifier? 3 | var type: Type 4 | } 5 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/TypeSystem.swift: -------------------------------------------------------------------------------- 1 | /// Describes the operations one can provide on types in the type system. 2 | public protocol TypeSystem { 3 | /// A type-system-specific notion of a context, which is used to resolve 4 | /// information about types. 5 | associatedtype Context 6 | 7 | /// "Baggage" associated with any type reference, which provides additional 8 | /// information that is specific to the type system. 9 | associatedtype TypeBaggage: Hashable 10 | 11 | /// Baggage associated with a resolved name, which is used by the type 12 | /// system to refer to the underlying entity. 13 | associatedtype ResolvedNameBaggage: Hashable 14 | 15 | /// A type within this type system. 16 | typealias TypeRef = Type 17 | 18 | /// Bind the names of a type in the given context, resolving names to the 19 | /// kind of entity (and associated baggage) providing resolved names for each 20 | /// identifier. 21 | func bind(_ type: TypeRef, in context: Context) -> TypeRef 22 | 23 | /// Resolve a type in context, binding any names, checking generic arguments, 24 | /// and producing complete substitution maps (for example). 25 | /// 26 | /// Note: we need some way of producing errors. 27 | func resolve(_ type: TypeRef, in context: Context) -> TypeRef 28 | 29 | /// Canonicalize a type in context, producing an equivalent type that 30 | /// reduces all syntactic sugar (including, e.g., type aliases, 31 | /// array/dictionary/optional sugar, parentheses, and so on). 32 | /// 33 | /// The canonical type produced from this operation is the language's notion 34 | /// of the type, which provides complete information for identifying the type 35 | /// independent of any context. A canonical type can be reasonably 36 | /// interpreted within any type system, without consulting system-specific 37 | /// baggage. 38 | /// 39 | /// Comparing two canonical types for equality determines whether 40 | /// the two types are semantic equivalent according to the language 41 | /// definition. 42 | func canonicalize(_ type: TypeRef, in context: Context) -> TypeRef 43 | 44 | /// Apply the given set of `substitutions` to the provided `type`, replacing 45 | /// each occurrence of a generic parameter within the type with its 46 | /// corresponding generic argument. 47 | func substitute( 48 | in type: TypeRef, 49 | with substitutions: SubstitutionMap 50 | ) -> TypeRef 51 | } 52 | -------------------------------------------------------------------------------- /Sources/SwiftTypeSystem/Types.swift: -------------------------------------------------------------------------------- 1 | public typealias Identifier = String 2 | 3 | public struct Type { 4 | public typealias TypeRef = Type 5 | 6 | /// The structure of the type, which mirrors the spelling of the type as 7 | /// written in the language. 8 | public let structure: Structure 9 | 10 | /// Additional "baggage" that provides more information about the type being 11 | /// described, which can only be interpreted by the specific type system. 12 | public var baggage: System.TypeBaggage? 13 | } 14 | 15 | extension Type { 16 | /// The kind of type, which provides a complete description of the Swift 17 | /// type system. 18 | public enum Structure { 19 | /// A referenced to a named type. 20 | /// 21 | /// This represents any named type, like 'Set', which always includes 22 | /// the name, but might also have the parent type (i.e., the type before 23 | /// the `.` in `A.B`) and generic arguments. 24 | /// 25 | /// - Parameters: 26 | /// - parent: The parent of this type, i.e., the enclosing type that is 27 | /// written before the `.` 28 | /// - name: The name of the type. 29 | /// - genericArguments: If present, the generic arguments provided in 30 | /// angle brackets ('<...>'). 31 | /// - kind: If present, describes what kind of entity is referenced by the 32 | /// name, i.e., a struct, generic parameter, associated type, and so on. 33 | /// - substitutions: If present, the complete set of substitutions applied 34 | /// to a generic type to produce a specialized type. 35 | indirect case named( 36 | parent: TypeRef?, 37 | name: Identifier, 38 | genericArguments: [TypeRef]?, 39 | kind: ResolvedName?, 40 | substitutions: SubstitutionMap? 41 | ) 42 | 43 | /// An optional type T?. 44 | indirect case optional(TypeRef) 45 | 46 | /// An array type [T]. 47 | indirect case array(TypeRef) 48 | 49 | /// A dictionary type [K:V]. 50 | indirect case dictionary(key: TypeRef, value: TypeRef) 51 | 52 | /// A function type (params) -> type. 53 | indirect case function( 54 | parameters: [FunctionTypeParameter], 55 | result: TypeRef, 56 | attributes: FunctionAttributes 57 | ) 58 | 59 | /// A tuple type (T1, T2, ..., TN), including a parenthesized type (T). 60 | indirect case tuple([TupleTypeElement]) 61 | 62 | /// A composition type A & B. 63 | indirect case composition([TypeRef]) 64 | 65 | /// An existential type 'any P'. 66 | indirect case existential(TypeRef) 67 | 68 | /// An opaque type 'some P'. 69 | indirect case opaque(TypeRef) 70 | 71 | /// A pack expansion T.... 72 | indirect case packExpansion(TypeRef) 73 | 74 | /// A metatype T.Type 75 | indirect case metatype(TypeRef) 76 | 77 | /// An existential metatype T.Protocol 78 | indirect case existentialMetatype(TypeRef) 79 | 80 | /// A placeholder type, spelled explicitly as '_'. 81 | /// 82 | /// This kind of type doesn't exist 83 | case placeholder 84 | 85 | /// An erroneous type, used in places where a type could not be determined. 86 | /// 87 | /// Note: compilers care deeply about this, because they need to be able 88 | /// to model errors at any point in the type hierarchy. However, it is 89 | /// inexpressible in the source language and most clients will deal with 90 | /// errors in a different way. 91 | case error 92 | 93 | /// An (unnamed generic parameter), which is identified by its "depth" (i.e., 94 | /// the number of generic parameter lists in enclosing contexts) and "index" 95 | /// (the number of generic parameters preceding it in its generic parameter 96 | /// list). 97 | /// 98 | /// Note: this doesn't appear in the surface language, but is present in 99 | /// the compiler and in runtime metadata when working with canonical 100 | /// types and generic signatures. 101 | case genericParameter(depth: Int, index: Int) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Tests/SwiftTypeSystemTests/SwiftTypeSystemTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import SwiftTypeSystem 3 | 4 | final class SwiftTypeSystemTests: XCTestCase { 5 | func testExample() throws { 6 | } 7 | } 8 | --------------------------------------------------------------------------------