Merge pull request #11623 from CodaFi/fundef
[stdlib]Custom message for recursive Strideable witness
diff --git a/stdlib/public/core/Stride.swift.gyb b/stdlib/public/core/Stride.swift.gyb
index eea5a78..375b831 100644
--- a/stdlib/public/core/Stride.swift.gyb
+++ b/stdlib/public/core/Stride.swift.gyb
@@ -23,6 +23,12 @@
}%
/// Conforming types are notionally continuous, one-dimensional
/// values that can be offset and measured.
+///
+/// - Important: The `Strideable` protocol provides default implementations for
+/// the equal-to (`==`) and less-than (`<`) operators that depend on the
+/// `Stride` type's implementations. If a type conforming to `Strideable`
+/// is its own `Stride` type, it must provide concrete implementations of
+/// the two operators to avoid infinite recursion.
public protocol ${Self} : ${Conformance} {
% if Self == '_Strideable':
/// A type that represents the distance between two values of `Self`.
@@ -55,6 +61,24 @@
% end
+extension Strideable where Stride == Self {
+ @available(*, deprecated, message: "Strideable conformance where 'Stride == Self' requires user-defined implementation of the '<' operator")
+ public static func < (x: Self, y: Self) -> Bool {
+ fatalError("""
+ Strideable conformance where 'Stride == Self' requires user-defined \
+ implementation of the '<' operator
+ """)
+ }
+
+ @available(*, deprecated, message: "Strideable conformance where 'Stride == Self' requires user-defined implementation of the '==' operator")
+ public static func == (x: Self, y: Self) -> Bool {
+ fatalError("""
+ Strideable conformance where 'Stride == Self' requires user-defined \
+ implementation of the '==' operator
+ """)
+ }
+}
+
extension Strideable {
@_inlineable
public static func < (x: Self, y: Self) -> Bool {
diff --git a/validation-test/stdlib/InvalidStrideable.swift b/validation-test/stdlib/InvalidStrideable.swift
new file mode 100644
index 0000000..3306f63
--- /dev/null
+++ b/validation-test/stdlib/InvalidStrideable.swift
@@ -0,0 +1,43 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift -emit-executable -DTEST_EQUATABLE -o %t/InvalidStrideableEq %s
+// RUN: ! %target-run %t/InvalidStrideableEq 2>&1 | %FileCheck %s --check-prefix=CHECK-EQUATABLE
+// RUN: %target-build-swift -emit-executable -DTEST_COMPARABLE -o %t/InvalidStrideableCmp %s
+// RUN: ! %target-run %t/InvalidStrideableCmp 2>&1 | %FileCheck %s --check-prefix=CHECK-COMPARABLE
+// REQUIRES: executable_test
+
+//
+// Check that a circular Strideable inheriting witnesses from Stdlib crashes
+// with a rich error message.
+//
+
+struct InvalidStrideable : Strideable, SignedNumeric {
+ typealias Magnitude = InvalidStrideable
+ init?<T>(exactly: T) where T : BinaryInteger { return nil }
+ var magnitude: InvalidStrideable { return self }
+
+ static func += (lhs: inout InvalidStrideable, rhs: InvalidStrideable) { }
+ static func -= (lhs: inout InvalidStrideable, rhs: InvalidStrideable) { }
+ static func *= (lhs: inout InvalidStrideable, rhs: InvalidStrideable) { }
+
+ static func + (lhs: InvalidStrideable, rhs: InvalidStrideable) -> InvalidStrideable { return rhs }
+ static func - (lhs: InvalidStrideable, rhs: InvalidStrideable) -> InvalidStrideable { return rhs }
+ static func * (lhs: InvalidStrideable, rhs: InvalidStrideable) -> InvalidStrideable { return rhs }
+
+ typealias IntegerLiteralType = Int
+ init(integerLiteral : Int) {}
+
+ typealias Stride = InvalidStrideable
+
+ init() {}
+
+ func distance(to rhs: InvalidStrideable) -> InvalidStrideable { return self }
+ func advanced(by n: InvalidStrideable) -> InvalidStrideable { return self }
+}
+
+#if TEST_EQUATABLE
+ // CHECK-EQUATABLE: fatal error: Strideable conformance where 'Stride == Self' requires user-defined implementation of the '==' operator
+ _ = InvalidStrideable() == InvalidStrideable()
+#else
+ // CHECK-COMPARABLE: fatal error: Strideable conformance where 'Stride == Self' requires user-defined implementation of the '<' operator
+ _ = InvalidStrideable() < InvalidStrideable() // Will trap with error message
+#endif