reflect: make Index and Slice accept strings

Fixes #3284.

R=golang-dev, r, rsc
CC=golang-dev
https://golang.org/cl/6643043
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index 5ddd6be..842b507 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -2036,6 +2036,24 @@
 	}
 }
 
+func TestIndex(t *testing.T) {
+	xs := []byte{1, 2, 3, 4, 5, 6, 7, 8}
+	v := ValueOf(xs).Index(3).Interface().(byte)
+	if v != xs[3] {
+		t.Errorf("xs.Index(3) = %v; expected %v", v, xs[3])
+	}
+	xa := [8]byte{10, 20, 30, 40, 50, 60, 70, 80}
+	v = ValueOf(xa).Index(2).Interface().(byte)
+	if v != xa[2] {
+		t.Errorf("xa.Index(2) = %v; expected %v", v, xa[2])
+	}
+	s := "0123456789"
+	v = ValueOf(s).Index(3).Interface().(byte)
+	if v != s[3] {
+		t.Errorf("s.Index(3) = %v; expected %v", v, s[3])
+	}
+}
+
 func TestSlice(t *testing.T) {
 	xs := []int{1, 2, 3, 4, 5, 6, 7, 8}
 	v := ValueOf(xs).Slice(3, 5).Interface().([]int)
@@ -2048,7 +2066,6 @@
 	if !DeepEqual(v[0:5], xs[3:]) {
 		t.Errorf("xs.Slice(3, 5)[0:5] = %v", v[0:5])
 	}
-
 	xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80}
 	v = ValueOf(&xa).Elem().Slice(2, 5).Interface().([]int)
 	if len(v) != 3 {
@@ -2060,6 +2077,11 @@
 	if !DeepEqual(v[0:6], xa[2:]) {
 		t.Errorf("xs.Slice(2, 5)[0:6] = %v", v[0:6])
 	}
+	s := "0123456789"
+	vs := ValueOf(s).Slice(3, 5).Interface().(string)
+	if vs != s[3:5] {
+		t.Errorf("s.Slice(3, 5) = %q; expected %q", vs, s[3:5])
+	}
 }
 
 func TestVariadic(t *testing.T) {
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 74addd1..be5d035 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -810,8 +810,10 @@
 	panic(&ValueError{"reflect.Value.Float", k})
 }
 
+var uint8Type = TypeOf(uint8(0)).(*commonType)
+
 // Index returns v's i'th element.
-// It panics if v's Kind is not Array or Slice or i is out of range.
+// It panics if v's Kind is not Array, Slice, or String or i is out of range.
 func (v Value) Index(i int) Value {
 	k := v.kind()
 	switch k {
@@ -852,6 +854,15 @@
 		fl |= flag(typ.Kind()) << flagKindShift
 		val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
 		return Value{typ, val, fl}
+
+	case String:
+		fl := v.flag&flagRO | flag(Uint8<<flagKindShift)
+		s := (*StringHeader)(v.val)
+		if i < 0 || i >= s.Len {
+			panic("reflect: string index out of range")
+		}
+		val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i)))
+		return Value{uint8Type, unsafe.Pointer(uintptr(val)), fl}
 	}
 	panic(&ValueError{"reflect.Value.Index", k})
 }
@@ -1437,7 +1448,7 @@
 }
 
 // Slice returns a slice of v.
-// It panics if v's Kind is not Array or Slice.
+// It panics if v's Kind is not Array, Slice, or String.
 func (v Value) Slice(beg, end int) Value {
 	var (
 		cap  int
@@ -1447,6 +1458,7 @@
 	switch k := v.kind(); k {
 	default:
 		panic(&ValueError{"reflect.Value.Slice", k})
+
 	case Array:
 		if v.flag&flagAddr == 0 {
 			panic("reflect.Value.Slice: slice of unaddressable array")
@@ -1455,13 +1467,25 @@
 		cap = int(tt.len)
 		typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice)))
 		base = v.val
+
 	case Slice:
 		typ = (*sliceType)(unsafe.Pointer(v.typ))
 		s := (*SliceHeader)(v.val)
 		base = unsafe.Pointer(s.Data)
 		cap = s.Cap
 
+	case String:
+		s := (*StringHeader)(v.val)
+		if beg < 0 || end < beg || end > s.Len {
+			panic("reflect.Value.Slice: string slice index out of bounds")
+		}
+		var x string
+		val := (*StringHeader)(unsafe.Pointer(&x))
+		val.Data = s.Data + uintptr(beg)
+		val.Len = end - beg
+		return Value{v.typ, unsafe.Pointer(&x), v.flag}
 	}
+
 	if beg < 0 || end < beg || end > cap {
 		panic("reflect.Value.Slice: slice index out of bounds")
 	}