context: document that WithValue's key must be comparable

Also, check it and explode earlier, rather than cryptic failures later.

Change-Id: I319a425f60e2bc9d005a187fbdbd153faa96411c
Reviewed-on: https://go-review.googlesource.com/21799
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Minux Ma <minux@golang.org>
diff --git a/src/context/context.go b/src/context/context.go
index 21dc867..c332e1f 100644
--- a/src/context/context.go
+++ b/src/context/context.go
@@ -39,6 +39,7 @@
 import (
 	"errors"
 	"fmt"
+	"reflect"
 	"sync"
 	"time"
 )
@@ -424,7 +425,12 @@
 //
 // Use context Values only for request-scoped data that transits processes and
 // APIs, not for passing optional parameters to functions.
-func WithValue(parent Context, key interface{}, val interface{}) Context {
+//
+// The provided key must be comparable.
+func WithValue(parent Context, key, val interface{}) Context {
+	if !reflect.TypeOf(key).Comparable() {
+		panic("key is not comparable")
+	}
 	return &valueCtx{parent, key, val}
 }
 
diff --git a/src/context/context_test.go b/src/context/context_test.go
index 573470e..0616704 100644
--- a/src/context/context_test.go
+++ b/src/context/context_test.go
@@ -586,3 +586,16 @@
 	cancel()
 	checkChildren("after cancelling WithTimeout child", ctx, 0)
 }
+
+func TestWithValueChecksKey(t *testing.T) {
+	panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
+	if panicVal == nil {
+		t.Error("expected panic")
+	}
+}
+
+func recoveredValue(fn func()) (v interface{}) {
+	defer func() { v = recover() }()
+	fn()
+	return
+}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 8e2fd6e..f1d19bb 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -215,7 +215,7 @@
 	"compress/gzip":            {"L4", "compress/flate"},
 	"compress/lzw":             {"L4"},
 	"compress/zlib":            {"L4", "compress/flate"},
-	"context":                  {"errors", "fmt", "sync", "time"},
+	"context":                  {"errors", "fmt", "reflect", "sync", "time"},
 	"database/sql":             {"L4", "container/list", "database/sql/driver"},
 	"database/sql/driver":      {"L4", "time"},
 	"debug/dwarf":              {"L4"},