1// run
2
3// Copyright 2019 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7// short-circuiting interface-to-concrete comparisons
8// will not miss panics
9
10package main
11
12import (
13	"log"
14	"strings"
15)
16
17func main() {
18	var (
19		x interface{}
20		p *int
21		s []int
22		l *interface{}
23		r []*int
24	)
25	tests := []struct {
26		name   string
27		errStr string
28		f      func()
29	}{
30		{"switch case", "", func() {
31			switch x {
32			case x.(*int):
33			}
34		}},
35		{"interface conversion", "", func() { _ = x == x.(error) }},
36		{"type assertion", "", func() { _ = x == x.(*int) }},
37		{"out of bounds", "", func() { _ = x == s[1] }},
38		{"nil pointer dereference #1", "", func() { _ = x == *p }},
39		// TODO(mdempsky): Restore "nil pointer dereference" check. The Go
40		// spec doesn't mandate an order for panics (or even panic
41		// messages), but left-to-right is less confusing to users.
42		{"nil pointer dereference #2", "", func() { _ = *l == r[0] }},
43		{"nil pointer dereference #3", "", func() { _ = *l == any(r[0]) }},
44	}
45
46	for _, tc := range tests {
47		testFuncShouldPanic(tc.name, tc.errStr, tc.f)
48	}
49}
50
51func testFuncShouldPanic(name, want string, f func()) {
52	defer func() {
53		e := recover()
54		if e == nil {
55			log.Fatalf("%s: comparison did not panic\n", name)
56		}
57		if have := e.(error).Error(); !strings.Contains(have, want) {
58			log.Fatalf("%s: wrong panic message: have %q, want %q\n", name, have, want)
59		}
60	}()
61	f()
62}
63