diff --git a/Library/Hylo/Core/PointerToMutable.hylo b/Library/Hylo/Core/PointerToMutable.hylo index 32161b46c..d973d098a 100644 --- a/Library/Hylo/Core/PointerToMutable.hylo +++ b/Library/Hylo/Core/PointerToMutable.hylo @@ -82,3 +82,15 @@ 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) + } + +} diff --git a/Sources/IR/Emitter.swift b/Sources/IR/Emitter.swift index 11f4552fd..045cf12e2 100644 --- a/Sources/IR/Emitter.swift +++ b/Sources/IR/Emitter.swift @@ -1123,7 +1123,7 @@ struct Emitter { case .down: emitStore(downcast: e, to: storage) case .pointerConversion: - unreachable("pointer to address conversion evaluates to a lvalue") + emitStore(pointerConversion: e, to: storage) } } @@ -1161,6 +1161,21 @@ struct Emitter { UNIMPLEMENTED() } + /// Inserts the IR for storing the value of `e` to `storage`. + private mutating func emitStore(pointerConversion e: CastExpr.ID, to storage: Operand) { + let x0 = emitLValue(pointerConversion: e) + + // Consuming a pointee requires a conformance to `Movable`. + let target = RemoteType(canonical(program[e].type))! + let movable = program.ast.movableTrait + if !program.conforms(target.bareType, to: movable, in: insertionScope!) { + report(.error(module.type(of: x0).ast, doesNotConformTo: movable, at: ast[e].site)) + return + } + + emitMove([.inout, .set], x0, to: storage, at: ast[e].site) + } + /// Inserts the IR for storing the value of `e` to `storage`. private mutating func emitStore(_ e: ConditionalExpr.ID, to storage: Operand) { let (success, failure) = emitTest(condition: ast[e].condition, in: AnyScopeID(e)) @@ -2072,18 +2087,23 @@ struct Emitter { private mutating func emitLValue(_ e: CastExpr.ID) -> Operand { switch ast[e].direction { case .pointerConversion: - let x0 = emitLValue(ast[e].left) - let x1 = insert(module.makeAccess(.sink, from: x0, at: ast[e].site))! - let x2 = insert(module.makeLoad(x1, at: ast[e].site))! - insert(module.makeEndAccess(x1, at: ast[e].site)) - let target = RemoteType(canonical(program[e].type))! - return insert(module.makePointerToAddress(x2, to: target, at: ast[e].site))! - + return emitLValue(pointerConversion: e) default: UNIMPLEMENTED() } } + /// Inserts the IR for lvalue `e`. + private mutating func emitLValue(pointerConversion e: CastExpr.ID) -> Operand { + let x0 = emitLValue(ast[e].left) + let x1 = insert(module.makeAccess(.sink, from: x0, at: ast[e].site))! + let x2 = insert(module.makeLoad(x1, at: ast[e].site))! + insert(module.makeEndAccess(x1, at: ast[e].site)) + + let target = RemoteType(canonical(program[e].type))! + return insert(module.makePointerToAddress(x2, to: target, at: ast[e].site))! + } + /// Inserts the IR for lvalue `e`. private mutating func emitLValue(_ e: InoutExpr.ID) -> Operand { emitLValue(ast[e].subject) diff --git a/Sources/IR/Mangling/Mangler.swift b/Sources/IR/Mangling/Mangler.swift index 11fccc73b..dfadc6881 100644 --- a/Sources/IR/Mangling/Mangler.swift +++ b/Sources/IR/Mangling/Mangler.swift @@ -295,9 +295,17 @@ struct Mangler { /// Writes the mangled representation of `c` to `output`. private mutating func write(constraint c: WhereClause.ConstraintExpr, to output: inout Output) { switch c { - case .conformance, .value: + case .value: UNIMPLEMENTED() + case .conformance(let lhs, let rhs): + write(operator: .conformanceConstraint, to: &output) + mangle(type: program[lhs].type, to: &output) + write(integer: rhs.count, to: &output) + for t in rhs { + mangle(type: program[t].type, to: &output) + } + case .equality(let lhs, let rhs): write(operator: .equalityConstraint, to: &output) mangle(type: program[lhs].type, to: &output) diff --git a/Sources/IR/Operands/Instruction/PointerToAddress.swift b/Sources/IR/Operands/Instruction/PointerToAddress.swift index 34f0d0dbd..f7e1d684c 100644 --- a/Sources/IR/Operands/Instruction/PointerToAddress.swift +++ b/Sources/IR/Operands/Instruction/PointerToAddress.swift @@ -49,14 +49,10 @@ extension Module { /// Creates a `pointer_to_address` anchored at `site` that converts `source`, which is a /// built-in pointer value, to an address of type `target`. - /// - /// - Requires: `target.access` is `.let`, `.inout`, or `.set` func makePointerToAddress( - _ source: Operand, - to target: RemoteType, - at site: SourceRange + _ source: Operand, to target: RemoteType, at site: SourceRange ) -> PointerToAddress { - precondition(AccessEffectSet([.let, .inout, .set]).contains(target.access)) + precondition(target.access != .yielded) return .init(source: source, target: target, site: site) } diff --git a/Tests/LibraryTests/TestCases/PointerToMutableTests.hylo b/Tests/LibraryTests/TestCases/PointerToMutableTests.hylo index a3f7613a8..32198a365 100644 --- a/Tests/LibraryTests/TestCases/PointerToMutableTests.hylo +++ b/Tests/LibraryTests/TestCases/PointerToMutableTests.hylo @@ -24,7 +24,16 @@ fun test_advance() { precondition(!(f == e)) } +fun test_pointee() { + let p = PointerToMutable.allocate(count: 1) + p.unsafe_initialize_pointee(fun (_ i: set Int) -> Void { &i = 42 }) + let y = p.unsafe_pointee() + precondition(42 == y) + p.deallocate() +} + public fun main() { test_advance_by_bytes() test_advance() + test_pointee() }