Skip to content

Commit

Permalink
Merge pull request #1571 from hylo-lang/array-buffer-init
Browse files Browse the repository at this point in the history
Implement minimal support for generic buffers
  • Loading branch information
kyouko-taiga authored Sep 1, 2024
2 parents 4d264ce + 22a95a4 commit 3a30da5
Show file tree
Hide file tree
Showing 58 changed files with 925 additions and 598 deletions.
12 changes: 6 additions & 6 deletions Sources/CodeGen/LLVM/TypeLowering.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ extension IR.Program {
///
/// - Requires: `t` is representable in LLVM.
func llvm(arrowType t: ArrowType, in module: inout SwiftyLLVM.Module) -> SwiftyLLVM.IRType {
precondition(t[.isCanonical])
precondition(t.isCanonical)
let e = llvm(t.environment, in: &module)
return SwiftyLLVM.StructType([module.ptr, e], in: &module)
}
Expand All @@ -49,7 +49,7 @@ extension IR.Program {
/// - Requires: `t` is representable in LLVM.
func llvm(bufferType t: BufferType, in module: inout SwiftyLLVM.Module) -> SwiftyLLVM.IRType {
let e = llvm(t.element, in: &module)
guard let n = t.count.asCompilerKnown(Int.self) else {
guard let n = ConcreteTerm(t.count)?.value as? Int else {
notLLVMRepresentable(t)
}
return SwiftyLLVM.ArrayType(n, e, in: &module)
Expand Down Expand Up @@ -85,7 +85,7 @@ extension IR.Program {
func llvm(
boundGenericType t: BoundGenericType, in module: inout SwiftyLLVM.Module
) -> SwiftyLLVM.IRType {
precondition(t[.isCanonical])
precondition(t.isCanonical)
precondition(t.base.base is ProductType)
return demandStruct(named: base.mangled(t), in: &module) { (m) in
llvm(fields: base.storage(of: t), in: &m)
Expand All @@ -96,7 +96,7 @@ extension IR.Program {
///
/// - Requires: `t` is representable in LLVM.
func llvm(productType t: ProductType, in module: inout SwiftyLLVM.Module) -> SwiftyLLVM.IRType {
precondition(t[.isCanonical])
precondition(t.isCanonical)
return demandStruct(named: base.mangled(t), in: &module) { (m) in
llvm(fields: AbstractTypeLayout(of: t, definedIn: base).properties, in: &m)
}
Expand All @@ -106,7 +106,7 @@ extension IR.Program {
///
/// - Requires: `t` is representable in LLVM.
func llvm(tupleType t: TupleType, in module: inout SwiftyLLVM.Module) -> SwiftyLLVM.IRType {
precondition(t[.isCanonical])
precondition(t.isCanonical)
let fs = llvm(fields: t.elements, in: &module)
return SwiftyLLVM.StructType(fs, in: &module)
}
Expand All @@ -122,7 +122,7 @@ extension IR.Program {
///
/// - Requires: `t` is representable in LLVM.
func llvm(unionType t: UnionType, in module: inout SwiftyLLVM.Module) -> SwiftyLLVM.IRType {
precondition(t[.isCanonical])
precondition(t.isCanonical)

var payload: SwiftyLLVM.IRType = SwiftyLLVM.StructType([], in: &module)
if t.isNever {
Expand Down
9 changes: 9 additions & 0 deletions Sources/FrontEnd/AST/AST.swift
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ public struct AST {
return UnionType([t, ^u])
}

/// Returns the Hylo type of an array of `t`.
///
/// - Requires: The Core library must have been loaded.
public func array(_ t: AnyType) -> BoundGenericType {
let b = coreType("Array")!
let e = self[b.decl].genericParameters[0]
return BoundGenericType(b, arguments: [e: .type(t)])
}

/// Returns the type named `name` defined in the core library or `nil` it does not exist.
///
/// - Requires: The Core library must have been loaded.
Expand Down
2 changes: 1 addition & 1 deletion Sources/FrontEnd/AST/Decl/SynthesizedFunctionDecl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public struct SynthesizedFunctionDecl: Hashable {
parameterizedBy genericParameters: [GenericParameterDecl.ID],
in scope: AnyScopeID
) {
precondition(type[.isCanonical])
precondition(type.isCanonical)
precondition(type.environment.base is TupleType)
self.type = type
self.genericParameters = genericParameters
Expand Down
35 changes: 20 additions & 15 deletions Sources/FrontEnd/CompileTimeValues/CompileTimeValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,40 @@ public enum CompileTimeValue: Hashable {
/// A type.
case type(AnyType)

/// An instance of a type known by the compiler (e.g. `Int`).
case compilerKnown(AnyHashable)
/// A term.
case term(AnyTerm)

/// Properties about the representation of self.
public var flags: ValueFlags {
switch self {
case .type(let t): return t.flags
case .term(let t): return t.flags
}
}

/// The payload of `.type`.
public var asType: AnyType? {
if case .type(let t) = self {
return t
} else {
return nil
}
if case .type(let v) = self { v } else { nil }
}

/// The payload of `.term`.
public var asTerm: AnyTerm? {
if case .term(let v) = self { v } else { nil }
}

/// `true` iff self is in canonical form.
public var isCanonical: Bool {
if let t = asType { t[.isCanonical] } else { true }
if let t = asType { t.isCanonical } else { true }
}

/// `true` if `self` is a `TypeVariable`.
public var isTypeVariable: Bool {
asType?.base is TypeVariable
self.asType?.base is TypeVariable
}

/// The payload of `.compilerKnown` as an instance of `T`.
public func asCompilerKnown<T>(_: T.Type) -> T? {
if case .compilerKnown(let v) = self {
return v as? T
} else {
return nil
}
ConcreteTerm(self.asTerm)?.value as? T
}

}
Expand All @@ -43,7 +48,7 @@ extension CompileTimeValue: CustomStringConvertible {
switch self {
case .type(let v):
return "\(v)"
case .compilerKnown(let v):
case .term(let v):
return "\(v)"
}
}
Expand Down
29 changes: 29 additions & 0 deletions Sources/FrontEnd/CompileTimeValues/ValueFlags.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/// Properties about the representation of a type or term.
public struct ValueFlags: Hashable, OptionSet {

public typealias RawValue = UInt8

public let rawValue: UInt8

public init(rawValue: UInt8) {
self.rawValue = rawValue
}

/// Returns the union of `l` with `r`.
public static func | (l: Self, r: Self) -> Self {
l.union(r)
}

/// The type contains one or more error types.
public static let hasError = ValueFlags(rawValue: 1 << 0)

/// The type contains open type variables.
public static let hasVariable = ValueFlags(rawValue: 1 << 1)

/// The type contains skolemized variables.
public static let hasSkolem = ValueFlags(rawValue: 1 << 2)

/// The type is not canonical.
public static let hasNonCanonical = ValueFlags(rawValue: 1 << 3)

}
107 changes: 107 additions & 0 deletions Sources/FrontEnd/Terms/AnyTerm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import Utils

/// A box wrapping a term.
private protocol TermBox {

/// Hashes the salient parts of the wrapped value into `hasher`.
func hash(into hasher: inout Hasher)

/// Returns whether the value wrapped inside `self` is equal to that wrapped inside `other`.
func equals<Other: TermBox>(_ other: Other) -> Bool

/// Returns the value wrapped inside `self` with its type erased.
func unwrap() -> any TermProtocol

/// Returns the value wrapped inside `self` as an instance of `T` or `nil` if that value has a
/// different type.
func unwrap<T: TermProtocol>(as: T.Type) -> T?

}

/// A box wrapping an instance of `Base`.
private struct ConcreteTermBox<Base: TermProtocol>: TermBox {

/// The value wrapped by this instance.
let base: Base

func hash(into hasher: inout Hasher) {
base.hash(into: &hasher)
}

func equals<Other: TermBox>(_ other: Other) -> Bool {
base == other.unwrap(as: Base.self)
}

func unwrap() -> any TermProtocol {
base
}

func unwrap<T: TermProtocol>(as: T.Type) -> T? {
base as? T
}

}

/// The compile-time representation of the value of an expression.
public struct AnyTerm {

/// A shorthand for `^ErrorTerm()`.
public static let error = ^ErrorTerm()

/// The value wrapped by this instance.
private var wrapped: TermBox

/// Creates a type-erased container wrapping the given instance.
///
/// - Parameter base: A type to wrap.
public init<T: TermProtocol>(_ base: T) {
if let t = base as? AnyTerm {
self.wrapped = t.wrapped
} else {
self.wrapped = ConcreteTermBox(base: base)
}
}

/// Accesses value wrapped by this instance.
///
/// The `base` property can be cast back to its original type using one of the type casting
/// operators (`as?`, `as!`, or `as`).
public var base: any TermProtocol {
wrapped.unwrap()
}

}

extension AnyTerm: TermProtocol {

public var flags: ValueFlags { base.flags }

}

extension AnyTerm: Equatable {

/// Returns whether `l` is syntactically equal to `r`.
public static func == (l: Self, r: Self) -> Bool {
l.wrapped.equals(r.wrapped)
}

}

extension AnyTerm: Hashable {

public func hash(into hasher: inout Hasher) {
wrapped.hash(into: &hasher)
}

}

extension AnyTerm: CustomStringConvertible {

public var description: String { String(describing: base) }

}

/// Creates a type-erased container wrapping the given instance.
public prefix func ^ <T: TermProtocol>(_ base: T) -> AnyTerm {
AnyTerm(base)
}
20 changes: 20 additions & 0 deletions Sources/FrontEnd/Terms/ConcreteTerm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// A box wrapping a concrete compile-time value.
public struct ConcreteTerm: TermProtocol {

/// The value of the term.
public let value: AnyHashable

/// Creates an instance with the given value.
public init(wrapping value: AnyHashable) {
self.value = value
}

public var flags: ValueFlags { .init() }

}

extension ConcreteTerm: CustomStringConvertible {

public var description: String { "\(value)" }

}
12 changes: 12 additions & 0 deletions Sources/FrontEnd/Terms/ErrorTerm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/// A term denoting a type checking error.
public struct ErrorTerm: TermProtocol {

public var flags: ValueFlags { .hasError }

}

extension ErrorTerm: CustomStringConvertible {

public var description: String { "_" }

}
26 changes: 26 additions & 0 deletions Sources/FrontEnd/Terms/GenericTermParameter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Utils

/// A generic type parameter.
public struct GenericTermParameter: TermProtocol {

/// The declaration that introduces the parameter.
public let decl: GenericParameterDecl.ID

/// The name of the parameter.
public let name: Incidental<String>

/// Creates an instance denoting the generic type parameter declared by `decl`.
public init(_ decl: GenericParameterDecl.ID, ast: AST) {
self.decl = decl
self.name = Incidental(ast[decl].baseName)
}

public var flags: ValueFlags { .hasSkolem }

}

extension GenericTermParameter: CustomStringConvertible {

public var description: String { name.value }

}
34 changes: 34 additions & 0 deletions Sources/FrontEnd/Terms/TermProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// A protocol describing the API of a Hylo term.
public protocol TermProtocol: Hashable {

/// Properties about the representation of `self`.
var flags: ValueFlags { get }

}

extension TermProtocol {

/// Creates an instance with the value of `container.base` or returns `nil` if that value has
/// a different type.
public init?(_ container: AnyTerm) {
if let t = container.base as? Self {
self = t
} else {
return nil
}
}

/// Creates an instance with the value of `container.base` or returns `nil` if either that value
/// has a different type or `container` is `nil`.
public init?(_ container: AnyTerm?) {
if let t = container.flatMap(Self.init(_:)) {
self = t
} else {
return nil
}
}

/// Returns whether the specified flags are raised on this term.
public subscript(fs: ValueFlags) -> Bool { flags.contains(fs) }

}
Loading

0 comments on commit 3a30da5

Please sign in to comment.