Skip to content
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

Implement minimal support for generic buffers #1571

Merged
merged 33 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
19875ca
Implement sugars for array types
kyouko-taiga Aug 24, 2024
e2ef40b
Rework the representation of compile-time values
kyouko-taiga Aug 25, 2024
87c333b
Extend substitution maps to contain term assignments
kyouko-taiga Aug 25, 2024
5c8a2ae
Remove unused 'hasRemoteType' type flag
kyouko-taiga Aug 25, 2024
a0de176
Remove unused 'hasGenericValueParameter' type flag
kyouko-taiga Aug 25, 2024
70e11ca
Simplify the representation of type flags
kyouko-taiga Aug 25, 2024
c732282
Rename 'TypeFlags' to 'ValueFlags'
kyouko-taiga Aug 25, 2024
d8ec597
Add value flags to compile-time terms
kyouko-taiga Aug 25, 2024
172d934
Assert that 'TypeChecker.canonical(_:in:)' returns canonical types
kyouko-taiga Aug 25, 2024
6c863e0
Remove dead code
kyouko-taiga Aug 25, 2024
251c00d
Store terms rather than arbitrary compile time values in 'BufferType'
kyouko-taiga Aug 25, 2024
eef47e2
Add value flags to compile-time values
kyouko-taiga Aug 26, 2024
678c6c6
Implement a term representing type checking errors
kyouko-taiga Aug 26, 2024
69e1a34
Implement a term representing skolems
kyouko-taiga Aug 26, 2024
00d2913
Substitute term variables during type reification
kyouko-taiga Aug 26, 2024
3ba5e47
Add a method to extend substitution tables with term assignments
kyouko-taiga Aug 26, 2024
6e8bc0d
Improve the textual representation of substitution maps
kyouko-taiga Aug 26, 2024
3cedfda
Rename properties of 'Solution' for consistency with 'SubstitutionMap'
kyouko-taiga Aug 26, 2024
8232733
Merge term flags in the representation of buffer types
kyouko-taiga Aug 26, 2024
14656c6
Merge term flags in the representation of bound generic types
kyouko-taiga Aug 26, 2024
5dbace7
Eliminate local boilerplate
kyouko-taiga Aug 26, 2024
2662ce9
Refactor unification to deduce arguments to generic value parameters
kyouko-taiga Aug 26, 2024
c81103d
Implement a helper to test the kindness of a generic parameter
kyouko-taiga Aug 26, 2024
4a40c91
Handle generic value parameters during quantifier elimination
kyouko-taiga Aug 26, 2024
0cfbf0c
Mangle generic term parameters
kyouko-taiga Aug 26, 2024
781fab9
Remove needless newlines
kyouko-taiga Aug 26, 2024
08d8eba
Implement an array constructor that accepts buffers
kyouko-taiga Aug 26, 2024
7907042
Fix typos
kyouko-taiga Aug 27, 2024
e435fd4
Remove dead code
kyouko-taiga Aug 27, 2024
a92df7a
Improve the diagnostic of invalid arguments in buffer type expressions
kyouko-taiga Aug 27, 2024
56b34e7
Test the construction of an array using a buffer
kyouko-taiga Aug 27, 2024
b41eb0e
Remove unused intersection operator on 'ValueFlags'
kyouko-taiga Aug 31, 2024
22a95a4
Remove unused setter on 'AnyType.base' and 'AnyTerm.base'
kyouko-taiga Sep 1, 2024
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
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

Check warning on line 59 in Sources/FrontEnd/Terms/AnyTerm.swift

View check run for this annotation

Codecov / codecov/patch

Sources/FrontEnd/Terms/AnyTerm.swift#L59

Added line #L59 was not covered by tests
} 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) }

Check warning on line 100 in Sources/FrontEnd/Terms/AnyTerm.swift

View check run for this annotation

Codecov / codecov/patch

Sources/FrontEnd/Terms/AnyTerm.swift#L100

Added line #L100 was not covered by tests

}

/// 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)" }

Check warning on line 18 in Sources/FrontEnd/Terms/ConcreteTerm.swift

View check run for this annotation

Codecov / codecov/patch

Sources/FrontEnd/Terms/ConcreteTerm.swift#L18

Added line #L18 was not covered by tests

}
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 }

Check warning on line 4 in Sources/FrontEnd/Terms/ErrorTerm.swift

View check run for this annotation

Codecov / codecov/patch

Sources/FrontEnd/Terms/ErrorTerm.swift#L4

Added line #L4 was not covered by tests

}

extension ErrorTerm: CustomStringConvertible {

public var description: String { "_" }

Check warning on line 10 in Sources/FrontEnd/Terms/ErrorTerm.swift

View check run for this annotation

Codecov / codecov/patch

Sources/FrontEnd/Terms/ErrorTerm.swift#L10

Added line #L10 was not covered by tests

}
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 }

Check warning on line 24 in Sources/FrontEnd/Terms/GenericTermParameter.swift

View check run for this annotation

Codecov / codecov/patch

Sources/FrontEnd/Terms/GenericTermParameter.swift#L24

Added line #L24 was not covered by tests

}
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

Check warning on line 27 in Sources/FrontEnd/Terms/TermProtocol.swift

View check run for this annotation

Codecov / codecov/patch

Sources/FrontEnd/Terms/TermProtocol.swift#L27

Added line #L27 was not covered by tests
}
}

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

Check warning on line 32 in Sources/FrontEnd/Terms/TermProtocol.swift

View check run for this annotation

Codecov / codecov/patch

Sources/FrontEnd/Terms/TermProtocol.swift#L32

Added line #L32 was not covered by tests

}
Loading