diff --git a/Package.swift b/Package.swift index 7ff2d95..f8a3fb8 100644 --- a/Package.swift +++ b/Package.swift @@ -21,6 +21,9 @@ let package = Package( .target( name: "SwiftTypeSystem", dependencies: []), + .target( + name: "SwiftRuntime", + dependencies: ["SwiftTypeSystem"]), .testTarget( name: "SwiftTypeSystemTests", dependencies: ["SwiftTypeSystem"]), diff --git a/Sources/SwiftRuntime/Metadata.swift b/Sources/SwiftRuntime/Metadata.swift new file mode 100644 index 0000000..fc57f9a --- /dev/null +++ b/Sources/SwiftRuntime/Metadata.swift @@ -0,0 +1,40 @@ +import SwiftTypeSystem + +public struct Metadata: TypeProtocol, Layout { + public typealias System = Runtime + typealias Layout = Kind + + let pointer: UnsafeRawPointer + + init(_ ptr: UnsafeRawPointer) { + self.pointer = ptr + } +} + +extension Metadata { + public var kind: Kind { + layout + } +} + +extension Metadata { + /// The structure of the type, which mirrors the spelling of the type as + /// written in the language. + public var structure: StructuralType { + switch kind { + case .tuple: + let elts = TupleMetadata(pointer).map { + TupleTypeElement( + // We can technically dig this out from the labels string in tuple. + name: nil, + type: $0.type + ) + } + + return .tuple(elts) + + default: + return .placeholder + } + } +} diff --git a/Sources/SwiftRuntime/MetadataValues.swift b/Sources/SwiftRuntime/MetadataValues.swift new file mode 100644 index 0000000..f18d14b --- /dev/null +++ b/Sources/SwiftRuntime/MetadataValues.swift @@ -0,0 +1,114 @@ +extension Metadata { + public struct Kind { + let value: Int + + init(_ value: Int) { + self.value = value + } + + static var isRuntimePrivate: Int { + 0x100 + } + + static var isNonHeap: Int { + 0x200 + } + + static var isNonType: Int { + 0x400 + } + + public static var `class`: Kind { + Kind(0x0) + } + + public static var `struct`: Kind { + Kind(0x0 | isNonHeap) + } + + public static var `enum`: Kind { + Kind(0x1 | isNonHeap) + } + + public static var optional: Kind { + Kind(0x2 | isNonHeap) + } + + public static var foreignClass: Kind { + Kind(0x3 | isNonHeap) + } + + public static var foreignReferenceType: Kind { + Kind(0x4 | isNonHeap) + } + + public static var opaque: Kind { + Kind(0x0 | isRuntimePrivate | isNonHeap) + } + + public static var tuple: Kind { + Kind(0x1 | isRuntimePrivate | isNonHeap) + } + + public static var function: Kind { + Kind(0x2 | isRuntimePrivate | isNonHeap) + } + + public static var existential: Kind { + Kind(0x3 | isRuntimePrivate | isNonHeap) + } + + public static var metatype: Kind { + Kind(0x4 | isRuntimePrivate | isNonHeap) + } + + public static var objcClassWrapper: Kind { + Kind(0x5 | isRuntimePrivate | isNonHeap) + } + + public static var existentialMetatype: Kind { + Kind(0x6 | isRuntimePrivate | isNonHeap) + } + + public static var extendedExistential: Kind { + Kind(0x7 | isRuntimePrivate | isNonHeap) + } + + public static var heapLocalVariable: Kind { + Kind(0x0 | isNonType) + } + + public static var heapGenericLocalVariable: Kind { + Kind(0x0 | isRuntimePrivate | isNonType) + } + + public static var errorObject: Kind { + Kind(0x1 | isRuntimePrivate | isNonType) + } + + public static var task: Kind { + Kind(0x2 | isRuntimePrivate | isNonType) + } + + public static var job: Kind { + Kind(0x3 | isRuntimePrivate | isNonType) + } + } +} + +extension Metadata.Kind: Equatable { + public static func ==(_ lhs: Metadata.Kind, _ rhs: Metadata.Kind) -> Bool { + // On Darwin platforms, the metadata kind for class types is the ObjC isa + // pointer value which is guaranteed to be >= 0x800. + switch (lhs.value, rhs.value) { + case (0x800..., 0x0): + return true + case (0x0, 0x800...): + return true + case (0x800..., 0x800...): + return true + default: + return lhs.value == rhs.value + } + } +} diff --git a/Sources/SwiftRuntime/Misc.swift b/Sources/SwiftRuntime/Misc.swift new file mode 100644 index 0000000..e9682be --- /dev/null +++ b/Sources/SwiftRuntime/Misc.swift @@ -0,0 +1,15 @@ +protocol Layout { + associatedtype Layout + + var pointer: UnsafeRawPointer { get } +} + +extension Layout { + var layout: Layout { + pointer.load(as: Layout.self) + } + + var trailing: UnsafeRawPointer { + pointer + MemoryLayout.size + } +} diff --git a/Sources/SwiftRuntime/Runtime.swift b/Sources/SwiftRuntime/Runtime.swift new file mode 100644 index 0000000..c0a25aa --- /dev/null +++ b/Sources/SwiftRuntime/Runtime.swift @@ -0,0 +1,49 @@ +import SwiftTypeSystem + +public struct Runtime: TypeSystem { + public typealias Context = () + public typealias TypeRef = Metadata + public typealias ResolvedNameBaggage = Never + + /// Bind the names of a type in the given context, resolving names to the + /// kind of entity (and associated baggage) providing resolved names for each + /// identifier. + public func bind(_ type: TypeRef, in context: Context) -> TypeRef { + type + } + + /// Resolve a type in context, binding any names, checking generic arguments, + /// and producing complete substitution maps (for example). + /// + /// Note: we need some way of producing errors. + public func resolve(_ type: TypeRef, in context: Context) -> TypeRef { + type + } + + /// Canonicalize a type in context, producing an equivalent type that + /// reduces all syntactic sugar (including, e.g., type aliases, + /// array/dictionary/optional sugar, parentheses, and so on). + /// + /// The canonical type produced from this operation is the language's notion + /// of the type, which provides complete information for identifying the type + /// independent of any context. A canonical type can be reasonably + /// interpreted within any type system, without consulting system-specific + /// baggage. + /// + /// Comparing two canonical types for equality determines whether + /// the two types are semantic equivalent according to the language + /// definition. + public func canonicalize(_ type: TypeRef, in context: Context) -> TypeRef { + type + } + + /// Apply the given set of `substitutions` to the provided `type`, replacing + /// each occurrence of a generic parameter within the type with its + /// corresponding generic argument. + public func substitute( + in type: TypeRef, + with substitutions: SubstitutionMap + ) -> TypeRef { + type + } +} diff --git a/Sources/SwiftRuntime/TupleMetadata.swift b/Sources/SwiftRuntime/TupleMetadata.swift new file mode 100644 index 0000000..7569502 --- /dev/null +++ b/Sources/SwiftRuntime/TupleMetadata.swift @@ -0,0 +1,47 @@ +public struct TupleMetadata: Layout { + typealias Layout = ( + base: Metadata.Layout, + numberOfElements: Int, + labels: UnsafePointer? + ) + + let pointer: UnsafeRawPointer + + init(_ ptr: UnsafeRawPointer) { + self.pointer = ptr + } +} + +extension TupleMetadata: RandomAccessCollection { + public struct Element { + let storage: (Metadata, Int) + + public var type: Metadata { + storage.0 + } + + public var offset: Int { + storage.1 + } + } + + public var startIndex: Int { + 0 + } + + public var endIndex: Int { + layout.numberOfElements + } + + public func index(after i: Int) -> Int { + i + 1 + } + + public func index(before i: Int) -> Int { + i - 1 + } + + public subscript(position: Int) -> Element { + (trailing + position * MemoryLayout.size).load(as: Element.self) + } +} diff --git a/Sources/SwiftTypeSystem/FunctionTypes.swift b/Sources/SwiftTypeSystem/FunctionTypes.swift index 80a505e..dc88eb8 100644 --- a/Sources/SwiftTypeSystem/FunctionTypes.swift +++ b/Sources/SwiftTypeSystem/FunctionTypes.swift @@ -1,7 +1,6 @@ - -extension Type { +public struct FunctionType { /// The calling convention used for a function. - public enum FunctionConvention { + public enum Convention { /// The normal Swift calling convention. /// /// This is the default calling convention for Swift functions, which is @@ -26,7 +25,7 @@ extension Type { } /// Attributes provided for a function. - public struct FunctionAttributes { + public struct Attributes { /// Whether this function is asynchronous. public var `async`: Bool @@ -40,10 +39,10 @@ extension Type { public var `sendable`: Bool /// The calling convention for the function. - public var convention: FunctionConvention = .swift + public var convention: Convention = .swift /// The global actor, such as `@MainActor`, on which this function runs. - public var globalActor: Type? + public var globalActor: System.Type? } /// The convention used to pass a parameter. @@ -61,7 +60,7 @@ extension Type { } /// A parameter within a function type. - public struct FunctionTypeParameter { + public struct Parameter { /// The argument label used when calling the function. /// /// Note: this is in the language grammar, but must either be omitted or diff --git a/Sources/SwiftTypeSystem/GenericArgument.swift b/Sources/SwiftTypeSystem/GenericArgument.swift index ec9df98..c049e44 100644 --- a/Sources/SwiftTypeSystem/GenericArgument.swift +++ b/Sources/SwiftTypeSystem/GenericArgument.swift @@ -1,4 +1,4 @@ /// A generic argument. public enum GenericArgument { - case type(Type) + case type(System.Type) } diff --git a/Sources/SwiftTypeSystem/GenericParameter.swift b/Sources/SwiftTypeSystem/GenericParameter.swift index d8e93d6..e07270c 100644 --- a/Sources/SwiftTypeSystem/GenericParameter.swift +++ b/Sources/SwiftTypeSystem/GenericParameter.swift @@ -1,6 +1,4 @@ public enum GenericParameter { - public typealias TypeRef = Type - /// A generic type parameter, e.g., . case type( name: Identifier?, diff --git a/Sources/SwiftTypeSystem/GenericRequirement.swift b/Sources/SwiftTypeSystem/GenericRequirement.swift index e1dad02..3bddcdf 100644 --- a/Sources/SwiftTypeSystem/GenericRequirement.swift +++ b/Sources/SwiftTypeSystem/GenericRequirement.swift @@ -1,4 +1,3 @@ - /// A constraint on the layout of a type, e.g., it is known to be a class, /// or be trivial with a fixed size. public enum LayoutConstraint { @@ -30,22 +29,20 @@ public enum LayoutConstraint { /// A generic requirement that is part of the generic signature of a type, /// e.g., `C: Collection` or `C.Element == C2.Element`. public enum GenericRequirement { - public typealias TypeRef = Type - /// A type bound such as `C: Collection` or `T: SomeSuperclass`. - case typeBound(TypeRef, TypeRef) + case typeBound(System.Type, System.Type) /// A same-type constraint such as `C.Element == C2.Element`. - case sameType(TypeRef, TypeRef) + case sameType(System.Type, System.Type) /// A same-shape constraint that ensures that two parameter packs have the /// same shape. /// /// Note: this does not have a spelling in the surface language. - case sameShape(TypeRef, TypeRef) + case sameShape(System.Type, System.Type) /// A layout constraint that states that a given type - case layout(TypeRef, LayoutConstraint) + case layout(System.Type, LayoutConstraint) /// A pack expansion of a generic requirement, e.g., /// `T.Element = U.Element...`. diff --git a/Sources/SwiftTypeSystem/Misc.swift b/Sources/SwiftTypeSystem/Misc.swift new file mode 100644 index 0000000..fb1cd08 --- /dev/null +++ b/Sources/SwiftTypeSystem/Misc.swift @@ -0,0 +1 @@ +public typealias Identifier = String diff --git a/Sources/SwiftTypeSystem/ResolvedName.swift b/Sources/SwiftTypeSystem/ResolvedName.swift index a9845c9..9d115da 100644 --- a/Sources/SwiftTypeSystem/ResolvedName.swift +++ b/Sources/SwiftTypeSystem/ResolvedName.swift @@ -1,43 +1,44 @@ -extension Type { - /// Describes how a named type has been resolved. - public struct ResolvedName { - public enum Kind { - /// A struct type. - case `struct` +// FIXME: Type was a really nice namespace, but this design forgoes that a +// little bit... - /// An enum type. - case `enum` +/// Describes how a named type has been resolved. +public struct ResolvedName { + public enum Kind { + /// A struct type. + case `struct` - /// An actor type. - case `actor` + /// An enum type. + case `enum` - /// A class type. - case `class` + /// An actor type. + case `actor` - /// A protocol type. - case `protocol` + /// A class type. + case `class` - /// An associated type. - case associatedType + /// A protocol type. + case `protocol` - /// A named generic parameter. - case genericParameter + /// An associated type. + case associatedType - /// A module. - case module + /// A named generic parameter. + case genericParameter - /// A typealias. - case `typealias` + /// A module. + case module - /// The 'Self' type. - case selfType - } + /// A typealias. + case `typealias` - /// The kind of entity to which this name resolved. - public let kind: Kind - - /// Additional baggage associated with the resolved name, which can - /// only be meaningfully interpreted by the specific type system. - public var baggage: System.ResolvedNameBaggage? + /// The 'Self' type. + case selfType } -} + + /// The kind of entity to which this name resolved. + public let kind: Kind + + /// Additional baggage associated with the resolved name, which can + /// only be meaningfully interpreted by the specific type system. + public var baggage: System.ResolvedNameBaggage? +} \ No newline at end of file diff --git a/Sources/SwiftTypeSystem/TupleTypes.swift b/Sources/SwiftTypeSystem/TupleTypes.swift index 992ca00..e9d8b95 100644 --- a/Sources/SwiftTypeSystem/TupleTypes.swift +++ b/Sources/SwiftTypeSystem/TupleTypes.swift @@ -1,4 +1,9 @@ public struct TupleTypeElement { - var name: Identifier? - var type: Type + public var name: Identifier? + public var type: System.TypeRef + + public init(name: Identifier?, type: System.TypeRef) { + self.name = name + self.type = type + } } diff --git a/Sources/SwiftTypeSystem/TypeSystem.swift b/Sources/SwiftTypeSystem/TypeSystem.swift index 938b121..7d56219 100644 --- a/Sources/SwiftTypeSystem/TypeSystem.swift +++ b/Sources/SwiftTypeSystem/TypeSystem.swift @@ -4,17 +4,13 @@ public protocol TypeSystem { /// information about types. associatedtype Context - /// "Baggage" associated with any type reference, which provides additional - /// information that is specific to the type system. - associatedtype TypeBaggage: Hashable + /// A type within this type system. + associatedtype TypeRef: TypeProtocol where TypeRef.System == Self /// Baggage associated with a resolved name, which is used by the type /// system to refer to the underlying entity. associatedtype ResolvedNameBaggage: Hashable - /// A type within this type system. - typealias TypeRef = Type - /// Bind the names of a type in the given context, resolving names to the /// kind of entity (and associated baggage) providing resolved names for each /// identifier. @@ -46,6 +42,6 @@ public protocol TypeSystem { /// corresponding generic argument. func substitute( in type: TypeRef, - with substitutions: SubstitutionMap + with substitutions: SubstitutionMap ) -> TypeRef } diff --git a/Sources/SwiftTypeSystem/Types.swift b/Sources/SwiftTypeSystem/Types.swift index 5681201..9fe523b 100644 --- a/Sources/SwiftTypeSystem/Types.swift +++ b/Sources/SwiftTypeSystem/Types.swift @@ -1,103 +1,95 @@ -public typealias Identifier = String - -public struct Type { - public typealias TypeRef = Type +public protocol TypeProtocol { + associatedtype System: TypeSystem /// The structure of the type, which mirrors the spelling of the type as /// written in the language. - public let structure: Structure - - /// Additional "baggage" that provides more information about the type being - /// described, which can only be interpreted by the specific type system. - public var baggage: System.TypeBaggage? + var structure: StructuralType { get } } -extension Type { - /// The kind of type, which provides a complete description of the Swift - /// type system. - public enum Structure { - /// A referenced to a named type. - /// - /// This represents any named type, like 'Set', which always includes - /// the name, but might also have the parent type (i.e., the type before - /// the `.` in `A.B`) and generic arguments. - /// - /// - Parameters: - /// - parent: The parent of this type, i.e., the enclosing type that is - /// written before the `.` - /// - name: The name of the type. - /// - genericArguments: If present, the generic arguments provided in - /// angle brackets ('<...>'). - /// - kind: If present, describes what kind of entity is referenced by the - /// name, i.e., a struct, generic parameter, associated type, and so on. - /// - substitutions: If present, the complete set of substitutions applied - /// to a generic type to produce a specialized type. - indirect case named( - parent: TypeRef?, - name: Identifier, - genericArguments: [TypeRef]?, - kind: ResolvedName?, - substitutions: SubstitutionMap? - ) - - /// An optional type T?. - indirect case optional(TypeRef) - - /// An array type [T]. - indirect case array(TypeRef) - - /// A dictionary type [K:V]. - indirect case dictionary(key: TypeRef, value: TypeRef) - - /// A function type (params) -> type. - indirect case function( - parameters: [FunctionTypeParameter], - result: TypeRef, - attributes: FunctionAttributes - ) - - /// A tuple type (T1, T2, ..., TN), including a parenthesized type (T). - indirect case tuple([TupleTypeElement]) - - /// A composition type A & B. - indirect case composition([TypeRef]) - - /// An existential type 'any P'. - indirect case existential(TypeRef) - - /// An opaque type 'some P'. - indirect case opaque(TypeRef) - - /// A pack expansion T.... - indirect case packExpansion(TypeRef) - - /// A metatype T.Type - indirect case metatype(TypeRef) - - /// An existential metatype T.Protocol - indirect case existentialMetatype(TypeRef) - - /// A placeholder type, spelled explicitly as '_'. - /// - /// This kind of type doesn't exist - case placeholder - - /// An erroneous type, used in places where a type could not be determined. - /// - /// Note: compilers care deeply about this, because they need to be able - /// to model errors at any point in the type hierarchy. However, it is - /// inexpressible in the source language and most clients will deal with - /// errors in a different way. - case error - - /// An (unnamed generic parameter), which is identified by its "depth" (i.e., - /// the number of generic parameter lists in enclosing contexts) and "index" - /// (the number of generic parameters preceding it in its generic parameter - /// list). - /// - /// Note: this doesn't appear in the surface language, but is present in - /// the compiler and in runtime metadata when working with canonical - /// types and generic signatures. - case genericParameter(depth: Int, index: Int) - } +/// The kind of type, which provides a complete description of the Swift +/// type system. +public enum StructuralType { + /// A referenced to a named type. + /// + /// This represents any named type, like 'Set', which always includes + /// the name, but might also have the parent type (i.e., the type before + /// the `.` in `A.B`) and generic arguments. + /// + /// - Parameters: + /// - parent: The parent of this type, i.e., the enclosing type that is + /// written before the `.` + /// - name: The name of the type. + /// - genericArguments: If present, the generic arguments provided in + /// angle brackets ('<...>'). + /// - kind: If present, describes what kind of entity is referenced by the + /// name, i.e., a struct, generic parameter, associated type, and so on. + /// - substitutions: If present, the complete set of substitutions applied + /// to a generic type to produce a specialized type. + case named( + parent: Type?, + name: Identifier, + genericArguments: [Type]?, + kind: ResolvedName?, + substitutions: SubstitutionMap? + ) + + /// An optional type T?. + case optional(Type) + + /// An array type [T]. + case array(Type) + + /// A dictionary type [K:V]. + case dictionary(key: Type, value: Type) + + /// A function type (params) -> type. + case function( + parameters: [FunctionType.Parameter], + result: Type, + attributes: FunctionType.Attributes + ) + + /// A tuple type (T1, T2, ..., TN), including a parenthesized type (T). + case tuple([TupleTypeElement]) + + /// A composition type A & B. + case composition([Type]) + + /// An existential type 'any P'. + case existential(Type) + + /// An opaque type 'some P'. + case opaque(Type) + + /// A pack expansion T.... + case packExpansion(Type) + + /// A metatype T.Type + case metatype(Type) + + /// An existential metatype T.Protocol + case existentialMetatype(Type) + + /// A placeholder type, spelled explicitly as '_'. + /// + /// This kind of type doesn't exist + case placeholder + + /// An erroneous type, used in places where a type could not be determined. + /// + /// Note: compilers care deeply about this, because they need to be able + /// to model errors at any point in the type hierarchy. However, it is + /// inexpressible in the source language and most clients will deal with + /// errors in a different way. + case error + + /// An (unnamed generic parameter), which is identified by its "depth" (i.e., + /// the number of generic parameter lists in enclosing contexts) and "index" + /// (the number of generic parameters preceding it in its generic parameter + /// list). + /// + /// Note: this doesn't appear in the surface language, but is present in + /// the compiler and in runtime metadata when working with canonical + /// types and generic signatures. + case genericParameter(depth: Int, index: Int) }