diff --git a/test/Inputs/Swiftskell.swift b/test/Inputs/Swiftskell.swift index 30bb79562b4a8..9e4b96bf3a8bc 100644 --- a/test/Inputs/Swiftskell.swift +++ b/test/Inputs/Swiftskell.swift @@ -55,9 +55,20 @@ public protocol Generator: ~Copyable { func next() -> Maybe } +/// Eager assertion function, to avoid autoclosures. +public func check(_ result: Bool, _ string: String? = nil, + _ file: String = #file, _ line: Int = #line) { + if result { return } + var msg = "assertion failure (\(file):\(line))" + if let extra = string { + msg += ":\t" + extra + } + fatalError(msg) +} + // MARK: Tuples public enum Pair: ~Copyable { - case elms(L, R) + case pair(L, R) } extension Pair: Copyable where L: Copyable, R: Copyable {} @@ -153,6 +164,8 @@ public struct Box: ~Copyable { /// MARK: Data.List +/// +/// A singly-linked list public enum List: ~Copyable { case cons(Element, Box>) case empty @@ -168,7 +181,7 @@ public enum List: ~Copyable { /// Pure Iteration extension List where Element: ~Copyable { /// Performs forward iteration through the list, accumulating a result value. - /// Returns f(xn,...,f(x2, f(x1, init))...), or init if the list is empty. + /// Returns f(xn,...,f(x2, f(x1, init))...), or `init` if the list is empty. public borrowing func foldl( init initial: consuming Out, _ f: (borrowing Element, consuming Out) -> Out) -> Out @@ -185,7 +198,7 @@ extension List where Element: ~Copyable { } /// Performs reverse iteration through the list, accumulating a result value. - /// Returns f(x1, f(x2,...,f(xn, init)...)) or init if the list is empty. + /// Returns f(x1, f(x2,...,f(xn, init)...)) or `init` if the list is empty. public borrowing func foldr( init initial: consuming Out, _ f: (borrowing Element, consuming Out) -> Out) -> Out @@ -228,30 +241,52 @@ extension List where Element: ~Copyable { /// Basic utilities extension List where Element: ~Copyable { /// Is this list empty? - public borrowing func empty() -> Bool { - switch self { - case .empty: return true - case .cons(_, _): return false + /// + /// Complexity: O(1) + public var isEmpty: Bool { + borrowing get { + switch self { + case .empty: true + case .cons(_, _): false + } } } /// How many elements are in this list? + /// + /// Complexity: O(n) public borrowing func length() -> Int { return foldl(init: 0) { $1 + 1 } } /// Pop the first element off the list, if present. + /// + /// Complexity: O(1) public consuming func pop() -> Optional>> { switch consume self { case .empty: .none - case let .cons(elm, tail): .elms(elm, tail.take()) + case let .cons(elm, tail): .pair(elm, tail.take()) } } - /// Push an element onto the list. + /// Push an element onto the front of the list. + /// + /// Complexity: O(1) public consuming func push(_ newHead: consuming Element) -> List { return List(newHead, self) } + + /// Produces a new list that is the reverse of this list. + /// + /// Complexity: O(n) + public consuming func reverse() -> List { + var new = List() + while case let .pair(head, tail) = pop() { + new = new.push(head) + self = tail + } + return new + } } extension List: Show where Element: Show & ~Copyable { diff --git a/test/Interpreter/moveonly_swiftskell.swift b/test/Interpreter/moveonly_swiftskell.swift index 7ed22656c7394..2b0659cede273 100644 --- a/test/Interpreter/moveonly_swiftskell.swift +++ b/test/Interpreter/moveonly_swiftskell.swift @@ -14,22 +14,13 @@ // RUN: -module-name E -o %t/E %target-rpath(%t) // RUN: %target-codesign %t/E // RUN: %target-codesign %t/%target-library-name(Swiftskell) -// RUN: %target-run %t/E %t/%target-library-name(Swiftskell) | %FileCheck %s +// RUN: %target-run %t/E %t/%target-library-name(Swiftskell) \ +// RUN: | %FileCheck %s --implicit-check-not destroy // REQUIRES: executable_test import Swiftskell -/// assertion function -func check(_ result: Bool, _ string: String? = nil, _ line: Int = #line) { - if result { return } - var msg = "assertion failure (line \(line))" - if let extra = string { - msg += ":\t" + extra - } - fatalError(msg) -} - /// Basic noncopyable type for testing. struct File: ~Copyable, Show { let id: Int @@ -37,6 +28,8 @@ struct File: ~Copyable, Show { self.id = id } func show() -> String { return id.show() } + + deinit { print("destroying file \(id)") } } @@ -51,14 +44,31 @@ func testListBasic() { var items = List(length: 5) { .init($0) } print(items.show()) // CHECK: [0, 1, 2, 3, 4, ] check(items.length() == 5) - check(!items.empty()) + check(!items.isEmpty) + + items = List(length: 5) { .init($0) } + // CHECK: destroying file 4 + // CHECK: destroying file 3 + // CHECK: destroying file 2 + // CHECK: destroying file 1 + // CHECK: destroying file 0 + + items = items.reverse() + check(items.length() == 5) + print(items.show()) // CHECK: [4, 3, 2, 1, 0, ] items = .empty + // CHECK: destroying file 0 + // CHECK: destroying file 1 + // CHECK: destroying file 2 + // CHECK: destroying file 3 + // CHECK: destroying file 4 + check(items.length() == 0) - check(items.empty()) + check(items.isEmpty) let nums = List().push(7).push(7).push(3) print(nums.show()) // CHECK: [7, 7, 3, ] - + }