From 2d6b34a0f58917040193afdfdb02a6e8759cbc45 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 16 Jan 2014 19:33:51 -0800 Subject: [PATCH] go.tools/go/types: report rhs type for comma-ok expressions Fixes golang/go#7060. R=adonovan CC=golang-codereviews https://golang.org/cl/53520043 --- go/types/api_test.go | 54 ++++++++++++++++++++++++++++++++++------- go/types/assignments.go | 4 +-- go/types/conversions.go | 2 +- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/go/types/api_test.go b/go/types/api_test.go index e85f517b..6742a3e2 100644 --- a/go/types/api_test.go +++ b/go/types/api_test.go @@ -41,7 +41,7 @@ func mustTypecheck(t *testing.T, path, source string, info *Info) string { return pkg.Name() } -func TestValues(t *testing.T) { +func TestValuesInfo(t *testing.T) { var tests = []struct { src string expr string // constant expression @@ -97,7 +97,7 @@ func TestValues(t *testing.T) { Types: make(map[ast.Expr]Type), Values: make(map[ast.Expr]exact.Value), } - name := mustTypecheck(t, "Values", test.src, &info) + name := mustTypecheck(t, "ValuesInfo", test.src, &info) // look for constant expression var expr ast.Expr @@ -125,12 +125,20 @@ func TestValues(t *testing.T) { } } -func TestCommaOkTypes(t *testing.T) { +func TestTypesInfo(t *testing.T) { var tests = []struct { src string - expr string // comma-ok expression - typ string // comma-ok value type + expr string // expression + typ string // value type }{ + // single-valued expressions of untyped constants + {`package b0; var x interface{} = false`, `false`, `bool`}, + {`package b1; var x interface{} = 0`, `0`, `int`}, + {`package b2; var x interface{} = 0.`, `0.`, `float64`}, + {`package b3; var x interface{} = 0i`, `0i`, `complex128`}, + {`package b4; var x interface{} = "foo"`, `"foo"`, `string`}, + + // comma-ok expressions {`package p0; var x interface{}; var _, _ = x.(int)`, `x.(int)`, `(int, bool)`, @@ -147,6 +155,8 @@ func TestCommaOkTypes(t *testing.T) { `<-c`, `(string, bool)`, }, + + // issue 6796 {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`, `x.(int)`, `(int, bool)`, @@ -167,13 +177,39 @@ func TestCommaOkTypes(t *testing.T) { `(<-c)`, `(string, bool)`, }, + + // issue 7060 + {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`, + `m[0]`, + `(string, bool)`, + }, + {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`, + `m[0]`, + `(string, bool)`, + }, + {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`, + `m[0]`, + `(string, bool)`, + }, + {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`, + `<-ch`, + `(string, bool)`, + }, + {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`, + `<-ch`, + `(string, bool)`, + }, + {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`, + `<-ch`, + `(string, bool)`, + }, } for _, test := range tests { info := Info{Types: make(map[ast.Expr]Type)} - name := mustTypecheck(t, "CommaOkTypes", test.src, &info) + name := mustTypecheck(t, "TypesInfo", test.src, &info) - // look for comma-ok expression type + // look for expression type var typ Type for e, t := range info.Types { if ExprString(e) == test.expr { @@ -314,7 +350,7 @@ func TestScopesInfo(t *testing.T) { } } -func TestInitOrder(t *testing.T) { +func TestInitOrderInfo(t *testing.T) { var tests = []struct { src string inits []string @@ -368,7 +404,7 @@ func TestInitOrder(t *testing.T) { for _, test := range tests { info := Info{} - name := mustTypecheck(t, "InitOrder", test.src, &info) + name := mustTypecheck(t, "InitOrderInfo", test.src, &info) // number of initializers must match if len(info.InitOrder) != len(test.inits) { diff --git a/go/types/assignments.go b/go/types/assignments.go index 73aa55b3..c1672440 100644 --- a/go/types/assignments.go +++ b/go/types/assignments.go @@ -131,7 +131,7 @@ func (check *checker) initVar(lhs *Var, x *operand) Type { return nil } - return lhs.typ + return x.typ } func (check *checker) assignVar(lhs ast.Expr, x *operand) Type { @@ -195,7 +195,7 @@ func (check *checker) assignVar(lhs ast.Expr, x *operand) Type { return nil } - return z.typ + return x.typ } // If returnPos is valid, initVars is called to type-check the assignment of diff --git a/go/types/conversions.go b/go/types/conversions.go index e90bbbda..839ae772 100644 --- a/go/types/conversions.go +++ b/go/types/conversions.go @@ -126,7 +126,7 @@ func isUintptr(typ Type) bool { func isUnsafePointer(typ Type) bool { // TODO(gri): Is this (typ.Underlying() instead of just typ) correct? - // The spec does't say so, but gc claims it is. See also + // The spec does not say so, but gc claims it is. See also // issue 6326. t, ok := typ.Underlying().(*Basic) return ok && t.kind == UnsafePointer