context: make DeadlineExceeded have a Timeout method

Fixes #14238

Change-Id: I1538bfb5cfa63e36a89df1f6eb9f5a0dcafb6ce5
Reviewed-on: https://go-review.googlesource.com/23256
Reviewed-by: Dave Cheney <dave@cheney.net>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/context/context.go b/src/context/context.go
index 9ff1950..169db74 100644
--- a/src/context/context.go
+++ b/src/context/context.go
@@ -144,7 +144,13 @@
 
 // DeadlineExceeded is the error returned by Context.Err when the context's
 // deadline passes.
-var DeadlineExceeded = errors.New("context deadline exceeded")
+var DeadlineExceeded error = deadlineExceededError{}
+
+type deadlineExceededError struct{}
+
+func (deadlineExceededError) Error() string { return "context deadline exceeded" }
+
+func (deadlineExceededError) Timeout() bool { return true }
 
 // An emptyCtx is never canceled, has no values, and has no deadline.  It is not
 // struct{}, since vars of this type must have distinct addresses.
diff --git a/src/context/context_test.go b/src/context/context_test.go
index 99456b1..90e78e5 100644
--- a/src/context/context_test.go
+++ b/src/context/context_test.go
@@ -594,3 +594,15 @@
 	fn()
 	return
 }
+
+func TestDeadlineExceededSupportsTimeout(t *testing.T) {
+	i, ok := DeadlineExceeded.(interface {
+		Timeout() bool
+	})
+	if !ok {
+		t.Fatal("DeadlineExceeded does not support Timeout interface")
+	}
+	if !i.Timeout() {
+		t.Fatal("wrong value for timeout")
+	}
+}