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