Commit 13e92e4d authored by Luuk van Dijk's avatar Luuk van Dijk

gc: Better typechecks and errors in switches.

Allow any type in switch on interface value.
Statically check typeswitch early.

Fixes #2423.
Fixes #2424.

R=rsc, dsymonds
CC=golang-dev
https://golang.org/cl/5339045
parent 820523d0
......@@ -810,8 +810,8 @@ walkswitch(Node *sw)
void
typecheckswitch(Node *n)
{
int top, lno;
Type *t;
int top, lno, ptr;
Type *t, *missing, *have;
NodeList *l, *ll;
Node *ncase, *nvar;
Node *def;
......@@ -854,21 +854,35 @@ typecheckswitch(Node *n)
typecheck(&ll->n, Erv | Etype);
if(ll->n->type == T || t == T)
continue;
setlineno(ncase);
switch(top) {
case Erv: // expression switch
defaultlit(&ll->n, t);
if(ll->n->op == OTYPE)
yyerror("type %T is not an expression", ll->n->type);
else if(ll->n->type != T && !eqtype(ll->n->type, t))
yyerror("case %lN in %T switch", ll->n, t);
else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) {
if(n->ntest)
yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
else
yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, n->ntest, ll->n->type, t);
}
break;
case Etype: // type switch
if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) {
;
} else if(ll->n->op != OTYPE && ll->n->type != T) {
} else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||?
yyerror("%lN is not a type", ll->n);
// reset to original type
ll->n = n->ntest->right;
} else if(!implements(ll->n->type, t, &missing, &have, &ptr)) {
if(have && !missing->broke && !have->broke)
yyerror("impossible type switch case: %lN cannot have dynamic type %T"
" (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT",
n->ntest->right, ll->n->type, missing->sym, have->sym, have->type,
missing->sym, missing->type);
else if(!missing->broke)
yyerror("impossible type switch case: %lN cannot have dynamic type %T"
" (missing %S method)", n->ntest->right, ll->n->type, missing->sym);
}
break;
}
......
......@@ -10,8 +10,8 @@ package main
func main() {
var x interface{}
switch t := x.(type) { // GC_ERROR "is not a type"
case 0: // GCCGO_ERROR "expected type"
switch t := x.(type) {
case 0: // ERROR "type"
t.x = 1 // ERROR "type interface \{\}|reference to undefined field or method"
}
}
// $G $D/$F.go
// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug375
// Copyright 2010 The Go Authors. All rights reserved.
// Copyright 2011 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.
// http://code.google.com/p/go/issues/detail?id=746
// Issue 2423
package main
type I interface { F() }
type T struct{}
func (T) F() {}
func main() {
switch I(T{}).(type) {
case interface{}:
var x interface{} = "hello"
switch x {
case "hello":
default:
println("FAIL")
}
}
// errchk $G -e $D/$F.go
// Copyright 2011 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 I interface {
M()
}
func bad() {
var i I
var s string
switch i {
case s: // ERROR "mismatched types string and I"
}
switch s {
case i: // ERROR "mismatched types I and string"
}
}
func good() {
var i interface{}
var s string
switch i {
case s:
}
switch s {
case i:
}
}
// errchk $G -e $D/$F.go
// Copyright 2011 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 I interface {
M()
}
func main(){
var x I
switch x.(type) {
case string: // ERROR "impossible"
println("FAIL")
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment