From 3fee9166d4ed6c5df4a54d9bcf8b037ba5a8c7d9 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 11 Sep 2013 10:03:40 -0700 Subject: [PATCH] go.tools/go/types: treat unsafe.Pointer like a pointer for receivers and embedding Also: Better error message for receiver type errors. R=adonovan CC=golang-dev https://golang.org/cl/13259044 --- go/types/testdata/decls2a.src | 10 ++++++-- go/types/testdata/decls3.src | 21 ++++++++-------- go/types/typexpr.go | 47 ++++++++++++++++++++++++----------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/go/types/testdata/decls2a.src b/go/types/testdata/decls2a.src index 962b5c43..6fe0f27d 100644 --- a/go/types/testdata/decls2a.src +++ b/go/types/testdata/decls2a.src @@ -27,10 +27,10 @@ type T1b struct { func (T1b) int /* ERROR "field and method" */ () {} type T1c struct { - unsafe.Pointer + time.Time } -func (T1c) Pointer /* ERROR "field and method" */ () int { return 0 } +func (T1c) Time /* ERROR "field and method" */ () int { return 0 } // Disabled for now: LookupFieldOrMethod will find Pointer even though // it's double-declared (it would cost extra in the common case to verify @@ -84,8 +84,14 @@ func (T5 /* ERROR "invalid receiver" */ ) m2() {} func (int /* ERROR "invalid receiver" */ ) m() {} func ([ /* ERROR "identifier" */ ]int) m() {} func (time /* ERROR "identifier" */ .Time) m() {} +func (*time /* ERROR "identifier" */ .Time) m() {} func (x interface /* ERROR "identifier" */ {}) m() {} +// Unsafe.Pointer is treated like a pointer when used as receiver type. +type UP unsafe.Pointer +func (UP /* ERROR "invalid" */ ) m1() {} +func (* /* ERROR "invalid" */ UP) m2() {} + // Double declarations across package files const c_double = 0 type t_double int diff --git a/go/types/testdata/decls3.src b/go/types/testdata/decls3.src index 5337c2b0..80d2bc8f 100644 --- a/go/types/testdata/decls3.src +++ b/go/types/testdata/decls3.src @@ -7,6 +7,7 @@ package decls3 import "unsafe" +import "fmt" // fields with the same name at the same level cancel each other out @@ -47,13 +48,13 @@ func issue4355() { } func _() { - type Pointer int - type A struct{ Pointer } - type B struct{ unsafe.Pointer } + type State int + type A struct{ State } + type B struct{ fmt.State } type T struct{ A; B } var t T -_ = t /* ERROR "ambiguous selector" */ .Pointer + _ = t /* ERROR "ambiguous selector" */ .State } // Embedded fields can be predeclared types. @@ -85,6 +86,7 @@ func _() { type I2 interface{} type P1 *int type P2 *int + type UP unsafe.Pointer type T1 struct { I1 @@ -94,13 +96,12 @@ func _() { * /* ERROR "cannot be a pointer" */ P2 } - // unsafe.Pointers are not regular pointers + // unsafe.Pointers are treated like regular pointers when embedded type T2 struct { - unsafe.Pointer - } - - type T3 struct { - *unsafe.Pointer + unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer + */* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer + UP /* ERROR "cannot be unsafe.Pointer" */ + * /* ERROR "cannot be unsafe.Pointer" */ UP } } diff --git a/go/types/typexpr.go b/go/types/typexpr.go index 7e7a6a05..b57d387e 100644 --- a/go/types/typexpr.go +++ b/go/types/typexpr.go @@ -140,24 +140,29 @@ func (check *checker) funcType(recv *ast.FieldList, ftyp *ast.FuncType, def *Nam // spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before) if t, _ := deref(recv.typ); t != Typ[Invalid] { - ok := true + var err string if T, _ := t.(*Named); T != nil { // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." - switch T.underlying.(type) { - case *Pointer, *Interface: - ok = false - } if T.obj.pkg != check.pkg { - ok = false + err = "type not defined in this package" + } else { + switch u := T.underlying.(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + err = "unsafe.Pointer" + } + case *Pointer, *Interface: + err = "pointer or interface type" + } } } else { - ok = false + err = "basic or unnamed type" } - if !ok { - // TODO(gri) provide better error message depending on error - check.errorf(recv.pos, "invalid receiver %s", recv) + if err != "" { + check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err) // ok to continue } } @@ -489,24 +494,38 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [ switch t := t.(type) { case *Basic: if t == Typ[Invalid] { - continue // ignore this field - error was reported before + // error was reported before + continue + } + // unsafe.Pointer is treated like a regular pointer + if t.kind == UnsafePointer { + check.errorf(pos, "anonymous field type cannot be unsafe.Pointer") + continue } add(f, nil, t.name, true, pos) + case *Named: // spec: "An embedded type must be specified as a type name // T or as a pointer to a non-interface type name *T, and T // itself may not be a pointer type." - switch t.Underlying().(type) { + switch u := t.Underlying().(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + check.errorf(pos, "anonymous field type cannot be unsafe.Pointer") + continue + } case *Pointer: check.errorf(pos, "anonymous field type cannot be a pointer") - continue // ignore this field + continue case *Interface: if isPtr { check.errorf(pos, "anonymous field type cannot be a pointer to an interface") - continue // ignore this field + continue } } add(f, nil, t.obj.name, true, pos) + default: check.invalidAST(pos, "anonymous field type %s must be named", typ) }