From 8ee9bca2729ead81da6bf5a18b87767ff396d1b7 Mon Sep 17 00:00:00 2001
From: Gergely Brautigam <skarlso777@gmail.com>
Date: Fri, 18 Jan 2019 21:43:56 +0100
Subject: [PATCH] cmd/compile: suppress typecheck errors in a type switch case
 with broken type
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

If a type switch case expression has failed typechecking, the case body is
likely to also fail with confusing or spurious errors. Suppress
typechecking the case body when this happens.

Fixes #28926

Change-Id: Idfdb9d5627994f2fd90154af1659e9a92bf692c4
Reviewed-on: https://go-review.googlesource.com/c/158617
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
---
 src/cmd/compile/internal/gc/swt.go | 16 ++++++++--------
 test/fixedbugs/issue28926.go       | 24 ++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 8 deletions(-)
 create mode 100644 test/fixedbugs/issue28926.go

diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 70fc66bf57..6a41885954 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -184,18 +184,11 @@ func typecheckswitch(n *Node) {
 			}
 		}
 
-		if n.Type == nil || n.Type.IsUntyped() {
-			// if the value we're switching on has no type or is untyped,
-			// we've already printed an error and don't need to continue
-			// typechecking the body
-			return
-		}
-
 		if top == Etype {
 			ll := ncase.List
 			if ncase.Rlist.Len() != 0 {
 				nvar := ncase.Rlist.First()
-				if ll.Len() == 1 && ll.First().Type != nil && !ll.First().Type.IsKind(TNIL) {
+				if ll.Len() == 1 && (ll.First().Type == nil || !ll.First().Type.IsKind(TNIL)) {
 					// single entry type switch
 					nvar.Type = ll.First().Type
 				} else {
@@ -203,6 +196,13 @@ func typecheckswitch(n *Node) {
 					nvar.Type = n.Type
 				}
 
+				if nvar.Type == nil || nvar.Type.IsUntyped() {
+					// if the value we're switching on has no type or is untyped,
+					// we've already printed an error and don't need to continue
+					// typechecking the body
+					continue
+				}
+
 				nvar = typecheck(nvar, ctxExpr|ctxAssign)
 				ncase.Rlist.SetFirst(nvar)
 			}
diff --git a/test/fixedbugs/issue28926.go b/test/fixedbugs/issue28926.go
new file mode 100644
index 0000000000..5a46bd307c
--- /dev/null
+++ b/test/fixedbugs/issue28926.go
@@ -0,0 +1,24 @@
+// errorcheck
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Stringer interface {
+	String() string
+}
+
+func main() {
+	var e interface{}
+	switch e := e.(type) {
+	case G: // ERROR "undefined: G"
+		e.M() // ok: this error should be ignored because the case failed its typecheck
+	case E: // ERROR "undefined: E"
+		e.D() // ok: this error should be ignored because the case failed its typecheck
+	case Stringer:
+		// ok: this error should not be ignored to prove that passing legs aren't left out
+		_ = e.(T) // ERROR "undefined: T"
+	}
+}
-- 
2.30.9