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

Add Array to Hylo standard library #1001

Merged
merged 86 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
ecce350
Add Array to Hylo standard library
camio Sep 12, 2023
81fabb3
Add explaination for DynamicBuffer's Movable conformance
camio Sep 12, 2023
040ab75
Add explanation for Array not conforming to Regular.
camio Sep 12, 2023
64d5065
Minor fix.
camio Sep 12, 2023
40c01c0
Commented out code blocked by #1003.
camio Sep 12, 2023
267e622
Use 'Void' as the header of arrays' out of line storage
kyouko-taiga Sep 13, 2023
d8234d4
Document 'Array''s properties
kyouko-taiga Sep 13, 2023
9250658
Reformat code
kyouko-taiga Sep 13, 2023
1ba88e0
Merge branch 'main' of github.com:hylo-lang/hylo into array
kyouko-taiga Sep 13, 2023
704a819
Simplify the computation of minimum capacity
kyouko-taiga Sep 13, 2023
984b344
Rename 'Array.reserveCapacity' to 'reserve_capacity'
kyouko-taiga Sep 13, 2023
7bf1296
Add missing explicit capture (wip)
kyouko-taiga Sep 13, 2023
68b42bd
Refactor the representation of bundle references
kyouko-taiga Sep 14, 2023
5d4432f
Make 'Module.isBorrowSet(_:)' internal
kyouko-taiga Sep 14, 2023
9d16eac
Simplify 'Module.makeProjectBundle'
kyouko-taiga Sep 14, 2023
abbae56
Refactor the representation of 'project_bundle'
kyouko-taiga Sep 14, 2023
bc772cc
Remove needless label
kyouko-taiga Sep 14, 2023
3f265e2
Refactor the initializers of 'Function.ID'
kyouko-taiga Sep 14, 2023
a2dbe17
Improve encapsulation
kyouko-taiga Sep 14, 2023
d188d66
Move 'BundleReference.swift' to 'Sources/IR/'
kyouko-taiga Sep 15, 2023
0c46981
Add an abstraction representing callees in IR
kyouko-taiga Sep 15, 2023
9b9bf16
Improve API and docs
kyouko-taiga Sep 15, 2023
c08f2bf
Improve API and docs
kyouko-taiga Sep 15, 2023
8b712e2
Fix comments
kyouko-taiga Sep 15, 2023
398ee2d
Generate IR for calls to method bundles
kyouko-taiga Sep 15, 2023
4d24d70
Add test case for exhausive branch returns
WalterSmuts Sep 14, 2023
c188534
Add special case for return type missing in DI
WalterSmuts Sep 15, 2023
2318020
Remove blanket failure for void/never return
WalterSmuts Sep 1, 2023
874e58c
Update Sources/IR/Analysis/Module+NormalizeObjectStates.swift
kyouko-taiga Sep 15, 2023
ac8c706
Request sink access on move sources during access reification
kyouko-taiga Sep 15, 2023
2eb9708
Mangle method bundle declarations
kyouko-taiga Sep 15, 2023
5d55f92
Stand up the call bundle reification pass
kyouko-taiga Sep 15, 2023
3fc7e32
Generate IR lowering method declarations
kyouko-taiga Sep 15, 2023
5d50084
Test call to method bundle
kyouko-taiga Sep 15, 2023
d6dbc43
Apply swift-format
kyouko-taiga Sep 15, 2023
38e8db8
Add hylo library product
koliyo Sep 15, 2023
62e9d66
Add public init to SourcePosition
koliyo Sep 15, 2023
2fee5ce
Refactor Hylo library target name
koliyo Sep 15, 2023
f68d3e2
Add a helper to get the lowered form of a conformance implementation
kyouko-taiga Sep 17, 2023
202506c
Add missing case to handle method implementations
kyouko-taiga Sep 17, 2023
71036cd
Implement IR support for custom conformances to 'Movable'
kyouko-taiga Sep 17, 2023
41dc065
Refactor 'Module.demandDeinitDeclaration'
kyouko-taiga Sep 17, 2023
b7937c2
Test custom conformance to 'Movable'
kyouko-taiga Sep 17, 2023
9fbb80a
Add test showing empty init behaviour
WalterSmuts Sep 14, 2023
95df4f7
Insert init directive for empty product type
WalterSmuts Sep 17, 2023
a0a6145
Refactor the gathering of traits bounds declared in generic environments
kyouko-taiga Sep 14, 2023
266602a
Rename 'TypedProgram.declaredConformances' to 'explicitConformance'
kyouko-taiga Sep 14, 2023
3fc6a0c
Compute conformances implied by constraints in generic environments
kyouko-taiga Sep 14, 2023
945ba3c
Refactor 'Emitter.emitMove(_:_:to:at:)'
kyouko-taiga Sep 17, 2023
e79b94d
Refactor 'Emitter.emitMove' to keep track of specialization arguments
kyouko-taiga Sep 17, 2023
89f0867
Simplify the representation of function identifiers
kyouko-taiga Sep 17, 2023
c2beb52
Rename 'TypedProgram.requirement(referredBy:)' to 'traitMember(referr…
kyouko-taiga Sep 17, 2023
a2236dc
Refine comments
kyouko-taiga Sep 17, 2023
3c2cfbe
Keep track of specialization arguments when generating moves
kyouko-taiga Sep 17, 2023
7d51317
Test use of conformance to 'Movable' in generic contexts
kyouko-taiga Sep 18, 2023
4a9101f
Keep track of specialization arguments when generating deinit calls
kyouko-taiga Sep 18, 2023
d7b856e
Test use of conformance to 'Deinitializable' in generic contexts
kyouko-taiga Sep 18, 2023
cd141ea
Apply swift-format
kyouko-taiga Sep 18, 2023
ac652e6
Write more concise docs
kyouko-taiga Sep 18, 2023
ed13d9a
Make 'AccessEffectSet.Elements' conform to 'Collection'
kyouko-taiga Sep 19, 2023
44e5135
Fix invalid application of parameter attributes
kyouko-taiga Sep 19, 2023
a2c1524
Generate IR for pointer conversions to sink addresses
kyouko-taiga Sep 19, 2023
588b60e
Implement mangling for conformance constraints
kyouko-taiga Sep 19, 2023
5b6eada
Implement a method to consume the pointee of a 'PointerToMutable'
kyouko-taiga Sep 19, 2023
722c306
Test 'PointerToMutable.unsafe_pointee()'
kyouko-taiga Sep 19, 2023
28553c0
Add a note for future deprecation
kyouko-taiga Sep 20, 2023
ab28738
Implement a pointee initialization method that doesn't use lambdas
kyouko-taiga Sep 20, 2023
01f292c
Test pointee initialization without lambdas
kyouko-taiga Sep 20, 2023
0732966
Apply code formatting conventions
kyouko-taiga Sep 20, 2023
fc925df
Fix condition to exit 'Array.reserve_capacity' early
kyouko-taiga Sep 20, 2023
24e1750
Implement previously blocked methods of 'Array'
kyouko-taiga Sep 20, 2023
b545f6f
Remove needless label
kyouko-taiga Sep 20, 2023
627a00a
Remove needless leading '_'
kyouko-taiga Sep 20, 2023
e7fdf1c
Add a comment about the correctness of 'reserve_capacity'
kyouko-taiga Sep 20, 2023
1da3689
Implement a subscript to access the elements of 'Array'
kyouko-taiga Sep 20, 2023
68d62eb
Fix the payload offset computation in 'DynamicBuffer'
kyouko-taiga Sep 20, 2023
23195b4
Mark mutating methods 'inout'
kyouko-taiga Sep 20, 2023
b49e5d7
Fix 'Array.reserve_capacity(_:)'
kyouko-taiga Sep 20, 2023
9500d32
Factorize Array element address computation
kyouko-taiga Sep 20, 2023
79c1d5a
Implement 'Array: Deinitializable'
kyouko-taiga Sep 20, 2023
cc35dbf
Test 'Array.append(_:)'
kyouko-taiga Sep 20, 2023
290ce67
Fix improperly named binding
kyouko-taiga Sep 20, 2023
1613b36
Fix the transpilation of 'Builtin.advanced_by_bytes'
kyouko-taiga Sep 20, 2023
8535a95
Remove needless spaces
kyouko-taiga Sep 20, 2023
5bfa32b
Implement a property to access the header of a 'DynamicBuffer'
kyouko-taiga Sep 20, 2023
6a90e54
Store the count of the array in the out-of-line storage
kyouko-taiga Sep 20, 2023
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
118 changes: 118 additions & 0 deletions Library/Hylo/Array.hylo
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/// An ordered, random-access collection.
public type Array<Element: Movable & Deinitializable>: Deinitializable {

/// The out-of-line storage of the array.
///
/// The header of the buffer indicates the number of elements contained in the array.
var storage: DynamicBuffer<Int, Element>

/// Creates a new, empty array.
public init() {
&storage = .new()
}

/// Deinitializes `self`.
public fun deinit() sink {
var i = 0
while i < count() {
&pointer_to_element(at: i).unsafe_pointee().deinit()
&i += 1
}
}

/// The number of elements in the array.
public fun count() -> Int {
if storage.capacity() == 0 { 0 } else { storage.header.copy() }
}

/// The number of elements that can be stored in the array before new storage must be allocated.
public fun capacity() -> Int {
return storage.capacity()
}

/// Reserves enough space to store `n` elements
public fun reserve_capacity(_ n: Int) inout {
if n < capacity() { return }

var new_capacity = max[1, capacity()].copy()
while new_capacity < n {
&new_capacity += new_capacity.copy()
}

// TODO: Call `self.copy()` directly in the lambda.
let c = count()
var new_storage = DynamicBuffer<Int, Element>(
capacity: new_capacity,
initializing_header_with: fun (_ h: set Int) -> Void { &h = c.copy() })

var i = 0
var e = storage.first_element_address()
var f = new_storage.first_element_address()
while i < count() {
f.unsafe_initialize_pointee(e.unsafe_pointee())
&e = e.advance(by: 1)
&f = f.advance(by: 1)
&i += 1
}

// Deinitializing the `self.storage` is safe at this point because all its elements must have
// been moved to `new_storage`.
&storage = new_storage
}

/// Adds a new element at the end of the array.
public fun append(_ source: sink Element) inout {
&reserve_capacity(count() + 1)
pointer_to_element(at: count()).unsafe_initialize_pointee(source)
&storage.header += 1
}

/// Accesses the element at `position`.
///
/// - Requires: `position` is in the range `0 ..< count()`.
public subscript(_ position: Int): Element {
let {
// precondition(position >= 0 && position < count())
pointer_to_element(at: position).unsafe[]
}
inout {
// precondition(position >= 0 && position < count())
pointer_to_element(at: position).unsafe[]
}
}

/// Returns the address of the element at `position`.
///
/// - Requires: `position` is in the range `0 ..< capacity()`.
fun pointer_to_element(at position: Int) -> PointerToMutable<Element> {
storage.first_element_address().advance(by: position)
}

}

/*

// TODO: Make Array conform to Regular instead of Deinitializable once #1002 is fixed.
// Currently that issue prevents the copy() function below from compiling.
//
// Error is "type 'Element' does not conform to trait 'Movable'"

public conformance Array: Equatable {

/// Returns `true` iff `other` has an equivalent value.
public fun infix== (_ other: Self) -> Bool {
// TODO
return true
}

}

public conformance Array: Copyable {
/// Returns an equivalent instance.
public fun copy() -> Self {
// TODO
.new()
}
}

*/
31 changes: 29 additions & 2 deletions Library/Hylo/Core/PointerToMutable.hylo
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ public type PointerToMutable<Pointee>: Regular {
}

/// Returns `self` offset forward by `n` array elements of `Pointee` type.
public fun advance( by n: Int ) -> Self {
public fun advance(by n: Int) -> Self {
let offset_in_bytes = MemoryLayout<Pointee>.stride() * n
return PointerToMutable<Pointee>.new(
base: Builtin.advanced_by_bytes_word( base, offset_in_bytes.value ) )
base: Builtin.advanced_by_bytes_word(base, offset_in_bytes.value))
}

/// Creates an instance that does not address any usable storage.
Expand Down Expand Up @@ -82,3 +82,30 @@ public conformance PointerToMutable: Equatable {
}

}

public extension PointerToMutable where Pointee: Movable {

/// Returns the value at the address represented by `self`, leaving the storage at this address
/// uninitialized.
///
/// Note: This method should be deprecated once nonmutating subscripts are implemented.
public fun unsafe_pointee() -> Pointee {
return base as* (remote sink Pointee)
}

/// Initialize the value at the address represented by `self` to `value`.
///
/// - Requires: the `MemoryLayout<Pointee>.size()` bytes starting at the address are uninitialized
/// and suitably aligned for `Pointee`.
public fun unsafe_initialize_pointee(_ value: sink Pointee) {
initialize<Pointee>(&(base as* (remote set Pointee)), to: value)
}

}

/// Initializes `x` to `y`.
///
/// - Note: This function is a workaround for the lack of `set` bindings (see #925).
fun initialize<T: Movable>(_ x: set T, to y: sink T) {
&x = y
}
36 changes: 31 additions & 5 deletions Library/Hylo/DynamicBuffer.hylo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/// - Warning: The deinitializer of `DynamicBuffer` does not deinitialize the elements that may
/// be stored in its payload. You must ensure that they are properly deinitialized before
/// `deinit` is called.
public type DynamicBuffer<Header: Deinitializable, Element>: Deinitializable {
public type DynamicBuffer<Header: Deinitializable, Element>: Deinitializable, Movable {

/// The description of payloads in `DynamicBuffer`s.
typealias BufferHeader = {
Expand All @@ -16,7 +16,7 @@ public type DynamicBuffer<Header: Deinitializable, Element>: Deinitializable {
static fun payload_offset() -> Int {
let a = MemoryLayout<Element>.alignment()
let s = MemoryLayout<BufferHeader>.size()
return s + (a - s % a)
return s + (a - s) % a
}

/// A pointer to the base of the buffer's out-of-line storage.
Expand Down Expand Up @@ -49,11 +49,12 @@ public type DynamicBuffer<Header: Deinitializable, Element>: Deinitializable {
}

/// Returns the address of the initial element.
/// - Precondition: `capacity != 0`
///
/// - Requires: `capacity() > 0`.
public fun first_element_address() -> PointerToMutable<Element> {
// TODO: Uncomment the following line when #995 is fixed
// precondition(self.capacity() == 0)
return PointerToMutable<Element>(type_punning: storage.advance(by_bytes: payload_offset()))
// precondition(self.capacity() > 0)
PointerToMutable<Element>(type_punning: storage.advance(by_bytes: payload_offset()))
}

/// Deinitializes `self`.
Expand All @@ -73,4 +74,29 @@ public type DynamicBuffer<Header: Deinitializable, Element>: Deinitializable {
return p.unsafe[].0.copy()
}

/// Accesses the header of `self`.
///
/// - Requires: `capacity() > 0`.
public property header: Header {
let { buffer_header().unsafe[].1 }
inout { &buffer_header().unsafe[].1 }
}

/// Returns the address of the `self`'s header.
fun buffer_header() -> PointerToMutable<BufferHeader> {
PointerToMutable<BufferHeader>(type_punning: storage)
}

}

// TODO: This trait was added as a workaround for #1002 since DynamicBuffer
// is initialized in the Array constructor
public conformance DynamicBuffer: Movable {

fun take_value(from source: sink Self) -> {self: Self, Void} {
// TODO: Fix defects preventing the following line from working
// &storage.base = source.storage.base
(self: source, ())
}

}
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ let package = Package(
products: [
.executable(name: "hc", targets: ["hc"]),
.executable(name: "hylo-demangle", targets: ["hylo-demangle"]),
.library(name: "Hylo", targets: ["Driver"]),
],

dependencies: [
Expand Down
7 changes: 2 additions & 5 deletions Sources/CodeGen/LLVM/Transpilation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ extension LLVM.Module {
let transpilation = declareFunction(ir.base.mangled(f), .init(from: parameters, in: &self))

configureAttributes(transpilation, transpiledFrom: f, of: m)
configureInputAttributes(transpilation.parameters.dropFirst(), transpiledFrom: f, in: m)
configureInputAttributes(transpilation.parameters.dropLast(), transpiledFrom: f, in: m)

return transpilation
}
Expand Down Expand Up @@ -903,10 +903,7 @@ extension LLVM.Module {
let base = llvm(s.operands[0])
let byteOffset = llvm(s.operands[1])
register[.register(i)] = insertGetElementPointerInBounds(
of: base,
typed: ptr,
indices: [byteOffset],
at: insertionPoint)
of: base, typed: i8, indices: [byteOffset], at: insertionPoint)

default:
unreachable("unexpected LLVM instruction '\(s.instruction)'")
Expand Down
45 changes: 25 additions & 20 deletions Sources/Core/AccessEffectSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ public struct AccessEffectSet: OptionSet, Hashable {

/// The weakest capability in `self`, or `nil` if `self` is empty.
public var weakest: AccessEffect? {
var s = elements
return s.next()
elements.first
}

/// Returns the strongest capability in `self` including `k`.
Expand Down Expand Up @@ -74,33 +73,39 @@ public struct AccessEffectSet: OptionSet, Hashable {

extension AccessEffectSet {

/// A sequence with the elements of an access effect set.
public struct Elements: Sequence, IteratorProtocol {
/// A collection with the elements of an access effect set.
public struct Elements: Collection {

public typealias Index = UInt8

public typealias Element = AccessEffect

/// The contents of the set being iterated over.
private let base: AccessEffectSet

/// The next effect returned by the iterator.
private var position: UInt8

/// Creates an iterator over `s`.
public init(_ s: AccessEffectSet) {
self.base = s
self.position = s.rawValue & (~s.rawValue + 1)
if self.position == 0 {
self.position = 1 << 7
}
}

/// Returns the next element in the sequence.
public mutating func next() -> AccessEffect? {
if position == (1 << 7) { return nil }
defer {
repeat {
position = position << 1
} while (position != (1 << 7)) && ((position & base.rawValue) != position)
}
return .init(rawValue: position)
public var startIndex: UInt8 {
base.rawValue & (~base.rawValue + 1)
}

public var endIndex: UInt8 {
1 << 7
}

public func index(after position: UInt8) -> UInt8 {
var next = position
repeat {
next = next << 1
} while (next != endIndex) && ((next & base.rawValue) != next)
return next
}

public subscript(position: UInt8) -> AccessEffect {
AccessEffect(rawValue: position)!
}

}
Expand Down
4 changes: 2 additions & 2 deletions Sources/Core/NativeInstruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ extension NativeInstruction: CustomStringConvertible {
return "fptosi_\(l)_\(r)"
case .zeroinitializer(let t):
return "zeroinitializer_\(t)"
case .advancedByBytes(let byteOffset):
return "advanced_by_bytes_\(byteOffset)"
case .advancedByBytes(let t):
return "advanced_by_bytes_\(t)"
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Core/Program.swift
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ extension Program {
scopes(from: scope).first(TranslationUnit.self)!
}

/// Returns the trait defining `d` iff `d` is a requirement. Otherwise, returns nil.
/// Returns the trait of which `d` is a member, or `nil` if `d` isn't member of a trait.
public func trait<T: DeclID>(defining d: T) -> TraitDecl.ID? {
switch d.kind {
case AssociatedTypeDecl.self, AssociatedValueDecl.self:
Expand Down
4 changes: 2 additions & 2 deletions Sources/Core/SourcePosition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ public struct SourcePosition: Hashable {
public let index: String.Index

/// Creates an instance with the given properties.
init(_ index: String.Index, in file: SourceFile) {
public init(_ index: String.Index, in file: SourceFile) {
self.file = file
self.index = index
}

/// Creates an instance referring to the given 1-based line and column numbers in `source`.
///
/// - Precondition: `line` and `column` denote a valid position in `source`.
init(line: Int, column: Int, in file: SourceFile) {
public init(line: Int, column: Int, in file: SourceFile) {
self.file = file
self.index = file.index(line: line, column: column)
}
Expand Down
Loading
Loading