Skip to content
This repository was archived by the owner on Jul 1, 2023. It is now read-only.

Commit ee09712

Browse files
authored
[Tensor] Add precondition in 'Tensor.init(arrayLiteral:)' to reject 'init()' calls. (#336)
A long-standing issue in Swift is that labeled variadic parameters can accept 0 arguments when a label does not exist. Here is a related discussion on Swift Evolution: [Should labeled variadic parameters accept 0 arguments?](https://forums.swift.org/t/should-labeled-variadic-parameters-accept-0-arguments/12500) When there is no `Tensor.init()`, an `init()` expression will resolve to a call to `init(arrayLiteral:)` with no arguments, which is semantically invalid for `Tensor`, `ShapedArray`, and `ShapedArraySlice`. Declaring an `init()` with an `@available(*, unavailable)` does not work becuase the type checker would still resolve `init()` calls to `init(arrayLiteral:)`. Before Swift supports finer control over labeled variadic parameters, the only thing we can do is to fail early at run-time. XCTest does not yet provide test utilities for crashers. We can add such a test utility along with tests for such run-time errors later. Resolves [TF-644](https://bugs.swift.org/browse/TF-644).
1 parent ef35d21 commit ee09712

File tree

3 files changed

+9
-7
lines changed

3 files changed

+9
-7
lines changed

Sources/TensorFlow/Core/ShapedArray.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -587,15 +587,15 @@ extension ShapedArray: RandomAccessCollection, MutableCollection {
587587
public subscript(index: Int) -> Element {
588588
get {
589589
precondition(!isScalar, "Scalar has no elements and cannot be subscripted.")
590-
precondition(index < endIndex, "ShapedArray index is out of range")
591-
precondition(index >= startIndex, "Negative ShapedArray index is out of range")
590+
precondition(index < endIndex, "ShapedArray index is out of range.")
591+
precondition(index >= startIndex, "Negative ShapedArray index is out of range.")
592592
return ShapedArraySlice(base: self, baseIndices: [index])
593593
}
594594
set {
595595
precondition(!isScalar, "Scalar has no elements and cannot be subscripted.")
596-
precondition(index < endIndex, "ShapedArray index is out of range")
597-
precondition(index >= startIndex, "Negative ShapedArray index is out of range")
598-
precondition(shape.dropFirst().elementsEqual(newValue.shape), "Element shape mismatch")
596+
precondition(index < endIndex, "ShapedArray index is out of range.")
597+
precondition(index >= startIndex, "Negative ShapedArray index is out of range.")
598+
precondition(shape.dropFirst().elementsEqual(newValue.shape), "Element shape mismatch.")
599599
let scalarIndex = self.scalarIndex(fromIndex: index)
600600
withUnsafeMutableBufferPointer { destBuffPtr in
601601
let ptr = destBuffPtr.baseAddress!.advanced(by: scalarIndex)
@@ -703,6 +703,7 @@ extension ShapedArray: ExpressibleByArrayLiteral where Scalar: TensorFlowScalar
703703
public typealias ArrayLiteralElement = _TensorElementLiteral<Scalar>
704704
@inlinable
705705
public init(arrayLiteral elements: _TensorElementLiteral<Scalar>...) {
706+
precondition(!elements.isEmpty, "Cannot create a 'ShapedArray' with no elements.")
706707
self = Tensor<Scalar>(_tensorElementLiterals: elements).array
707708
}
708709
}
@@ -836,7 +837,7 @@ public struct ShapedArraySlice<Scalar>: _ShapedArrayProtocol {
836837
baseIndices indices: __owned [Int] = [],
837838
bounds: Range<Int>? = nil
838839
) {
839-
precondition(indices.count <= base.rank, "Number of base indices exceeds base rank")
840+
precondition(indices.count <= base.rank, "Number of base indices exceeds base rank.")
840841
precondition(
841842
zip(base.shape, indices).allSatisfy { $1 >= 0 && $1 < $0 },
842843
"Base indices are out of range")
@@ -1065,6 +1066,7 @@ extension ShapedArraySlice: ExpressibleByArrayLiteral where Scalar: TensorFlowSc
10651066
public typealias ArrayLiteralElement = _TensorElementLiteral<Scalar>
10661067
@inlinable
10671068
public init(arrayLiteral elements: _TensorElementLiteral<Scalar>...) {
1069+
precondition(!elements.isEmpty, "Cannot create a 'ShapedArraySlice' with no elements.")
10681070
self.init(base: Tensor(_tensorElementLiterals: elements).array)
10691071
}
10701072
}

Sources/TensorFlow/Core/Tensor.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ extension Tensor: ExpressibleByArrayLiteral {
398398
/// Creates a tensor initialized with the given elements.
399399
@inlinable
400400
public init(arrayLiteral elements: _TensorElementLiteral<Scalar>...) {
401+
precondition(!elements.isEmpty, "Cannot create a 'Tensor' with no elements.")
401402
self.init(_tensorElementLiterals: elements)
402403
}
403404
}

Tests/TensorFlowTests/TensorTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ final class TensorTests: XCTestCase {
2525
}
2626
return b
2727
}
28-
2928
XCTAssertEqual(0, selectValue(true).scalar)
3029
}
3130

0 commit comments

Comments
 (0)